diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a4c92e2..e9aad43 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -91,6 +91,11 @@ jobs: - name: Build and pack static resources run: | + export COMMIT=`git rev-parse HEAD` + export VERSION=`git describe --tags | sed 's/^v//'` + sed -i "s/\$COMMIT/$COMMIT/g" ./web/src/config/version.json + sed -i "s/\$VERSION/$VERSION/g" ./web/src/config/version.json + cd ./web npm install npm run build-prod @@ -115,20 +120,20 @@ jobs: - name: Prepare release note run: | - wget -q https://1248.ink/Tools/release.js - node release.js ${{ github.ref_name }} + export REF_NAME=`git describe --tags` + node ./scripts/release.js $REF_NAME - name: Pack releases run: | mv ./built ./releases/built cd ./releases - sudo apt install zip tar -y - tar -zcf server_darwin_arm64.tar.gz server_darwin_arm64 ./built - tar -zcf server_darwin_amd64.tar.gz server_darwin_amd64 ./built - tar -zcf server_linux_arm.tar.gz server_linux_arm ./built - tar -zcf server_linux_i386.tar.gz server_linux_i386 ./built - tar -zcf server_linux_arm64.tar.gz server_linux_arm64 ./built - tar -zcf server_linux_amd64.tar.gz server_linux_amd64 ./built + sudo apt install zip tar pigz -y + tar -cpf server_darwin_arm64.tar.gz server_darwin_arm64 ./built + tar -cpf server_darwin_amd64.tar.gz server_darwin_amd64 ./built + tar -cpf server_linux_arm.tar.gz server_linux_arm ./built + tar -cpf server_linux_i386.tar.gz server_linux_i386 ./built + tar -cpf server_linux_arm64.tar.gz server_linux_arm64 ./built + tar -cpf server_linux_amd64.tar.gz server_linux_amd64 ./built zip -r -9 -q server_windows_arm.zip server_windows_arm.exe ./built zip -r -9 -q server_windows_i386.zip server_windows_i386.exe ./built zip -r -9 -q server_windows_arm64.zip server_windows_arm64.exe ./built @@ -158,3 +163,9 @@ jobs: name: | darwin_arm64 darwin_amd64 + + - name: Update version info + env: + RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }} + run: | + curl -X POST -H "Authorization: $RELEASE_TOKEN" --retry 10 -m 60 -o /dev/null https://1248.ink/spark/release > /dev/null 2>&1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 411b0af..d719ac4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +## v0.2.0 + +* Add: zmodem(lrzsz) support for terminal. +* Add: update notification (won't auto update). +* Optimize: protocol of terminal and desktop. +* Optimize: experience of explorer. +* Remove: CryptoJS. + +* 新增:终端支持zmodem协议(lrzsz)。 +* 新增:版本更新通知(不会自动更新)。 +* 优化:终端和桌面端的通信协议。 +* 优化:文件管理器的使用体验。 +* 移除:CryptoJS。 + + + ## v0.1.9 * Add: special keys for terminal. diff --git a/LICENSE b/LICENSE index 4508590..84d3e4a 100644 --- a/LICENSE +++ b/LICENSE @@ -23,56 +23,3 @@ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -------- - -utils/melody are copied and modified from olahol/melody. - -Copyright (c) 2015 Ola Holmström. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -------- - -utils/cmap are copied and modified from orcaman/concurrent-map. - -The MIT License (MIT) - -Copyright (c) 2014 streamrail - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/client/common/common.go b/client/common/common.go index c3d9553..f8211c6 100644 --- a/client/common/common.go +++ b/client/common/common.go @@ -4,6 +4,7 @@ import ( "Spark/client/config" "Spark/modules" "Spark/utils" + "encoding/binary" "encoding/hex" "errors" ws "github.com/gorilla/websocket" @@ -73,6 +74,25 @@ func (wsConn *Conn) SendPack(pack any) error { return wsConn.WriteMessage(ws.BinaryMessage, data) } +func (wsConn *Conn) SendRawData(event, data []byte, service byte, op byte) error { + Mutex.Lock() + defer Mutex.Unlock() + if WSConn == nil { + return errors.New(`${i18n|COMMON.DISCONNECTED}`) + } + buffer := make([]byte, 24) + copy(buffer[6:22], event) + copy(buffer[:4], []byte{34, 22, 19, 17}) + buffer[4] = service + buffer[5] = op + binary.BigEndian.PutUint16(buffer[22:24], uint16(len(data))) + buffer = append(buffer, data...) + + wsConn.SetWriteDeadline(utils.Now.Add(5 * time.Second)) + defer wsConn.SetWriteDeadline(time.Time{}) + return wsConn.WriteMessage(ws.BinaryMessage, buffer) +} + func (wsConn *Conn) SendCallback(pack, prev modules.Packet) error { if len(prev.Event) > 0 { pack.Event = prev.Event diff --git a/client/core/core.go b/client/core/core.go index 84b3fec..7c67362 100644 --- a/client/core/core.go +++ b/client/core/core.go @@ -161,6 +161,18 @@ func handleWS(wsConn *common.Conn) error { golog.Error(err) return nil } + if service, op, isBinary := utils.CheckBinaryPack(data); isBinary && len(data) > 24 { + event := hex.EncodeToString(data[6:22]) + switch service { + case 20: + case 21: + switch op { + case 0: + inputRawTerminal(data[24:], event) + } + } + continue + } data, err = utils.Decrypt(data, wsConn.GetSecret()) if err != nil { golog.Error(err) diff --git a/client/core/device.go b/client/core/device.go index 19bd306..be30766 100644 --- a/client/core/device.go +++ b/client/core/device.go @@ -179,16 +179,16 @@ func GetDevice() (*modules.Device, error) { } localIP, err := GetLocalIP() if err != nil { - localIP = `unknown` + localIP = `` } macAddr, err := GetMacAddress() if err != nil { - macAddr = `unknown` + macAddr = `` } cpuInfo, err := GetCPUInfo() if err != nil { cpuInfo = modules.CPU{ - Model: `unknown`, + Model: ``, Usage: 0, } } @@ -221,11 +221,11 @@ func GetDevice() (*modules.Device, error) { } hostname, err := os.Hostname() if err != nil { - hostname = `unknown` + hostname = `` } username, err := user.Current() if err != nil { - username = &user.User{Username: `unknown`} + username = &user.User{Username: ``} } else { slashIndex := strings.Index(username.Username, `\`) if slashIndex > -1 && slashIndex+1 < len(username.Username) { @@ -252,7 +252,7 @@ func GetPartialInfo() (*modules.Device, error) { cpuInfo, err := GetCPUInfo() if err != nil { cpuInfo = modules.CPU{ - Model: `unknown`, + Model: ``, Usage: 0, } } diff --git a/client/core/handler.go b/client/core/handler.go index ee9957d..60d69b0 100644 --- a/client/core/handler.go +++ b/client/core/handler.go @@ -370,3 +370,7 @@ func execCommand(pack modules.Packet, wsConn *common.Conn) { proc.Process.Release() } } + +func inputRawTerminal(pack []byte, event string) { + terminal.InputRawTerminal(pack, event) +} diff --git a/client/service/desktop/desktop.go b/client/service/desktop/desktop.go index ead6781..7ea8536 100644 --- a/client/service/desktop/desktop.go +++ b/client/service/desktop/desktop.go @@ -33,20 +33,22 @@ type message struct { frame *[]*[]byte } -// +---------+---------+----------+----------+------------+---------+---------+---------+---------+-------+ -// | magic | OP code | event id | img type | img length | x | y | width | height | image | -// +---------+---------+----------+----------+------------+---------+---------+---------+---------+-------+ -// | 5 bytes | 1 byte | 16 bytes | 2 bytes | 2 bytes | 2 bytes | 2 bytes | 2 bytes | 2 bytes | - | -// +---------+---------+----------+----------+------------+---------+---------+---------+---------+-------+ +// packet explanation: + +// +---------+---------+----------+-------------+----------+---------+---------+---------+---------+-------+ +// | magic | op code | event id | body length | img type | x | y | width | height | image | +// +---------+---------+----------+-------------+----------+---------+---------+---------+---------+-------+ +// | 5 bytes | 1 byte | 16 bytes | 2 bytes | 2 bytes | 2 bytes | 2 bytes | 2 bytes | 2 bytes | - | +// +---------+---------+----------+-------------+----------+---------+---------+---------+---------+-------+ // magic: // []byte{34, 22, 19, 17, 20} -// OP code: -// 00: first part of a frame -// 01: rest parts of a frame -// 02: set resolution of every frame -// 03: JSON string (only for server) +// op code: +// 00: first part of a frame, device -> browser +// 01: rest parts of a frame, device -> browser +// 02: set resolution of every frame, device -> browser +// 03: JSON string, server -> browser // img type: // 0: raw image @@ -167,12 +169,12 @@ func imageCompare(img, prev *image.RGBA, compress bool) []*[]byte { for _, rect := range diff { block := getImageBlock(img, rect, compress) buf := make([]byte, 12) + binary.BigEndian.PutUint16(buf[0:2], uint16(len(block)+10)) if compress { - binary.BigEndian.PutUint16(buf[0:2], uint16(1)) + binary.BigEndian.PutUint16(buf[2:4], uint16(1)) } else { - binary.BigEndian.PutUint16(buf[0:2], uint16(0)) + binary.BigEndian.PutUint16(buf[2:4], uint16(0)) } - binary.BigEndian.PutUint16(buf[2:4], uint16(len(block))) binary.BigEndian.PutUint16(buf[4:6], uint16(rect.Min.X)) binary.BigEndian.PutUint16(buf[6:8], uint16(rect.Min.Y)) binary.BigEndian.PutUint16(buf[8:10], uint16(rect.Size().X)) @@ -197,12 +199,12 @@ func splitFullImage(img *image.RGBA, compress bool) []*[]byte { width := utils.If(x+blockSize > imgWidth, imgWidth-x, blockSize) block := getImageBlock(img, image.Rect(x, y, x+width, y+height), compress) buf := make([]byte, 12) + binary.BigEndian.PutUint16(buf[0:2], uint16(len(block)+10)) if compress { - binary.BigEndian.PutUint16(buf[0:2], uint16(1)) + binary.BigEndian.PutUint16(buf[2:4], uint16(1)) } else { - binary.BigEndian.PutUint16(buf[0:2], uint16(0)) + binary.BigEndian.PutUint16(buf[2:4], uint16(0)) } - binary.BigEndian.PutUint16(buf[2:4], uint16(len(block))) binary.BigEndian.PutUint16(buf[4:6], uint16(x)) binary.BigEndian.PutUint16(buf[6:8], uint16(y)) binary.BigEndian.PutUint16(buf[8:10], uint16(width)) @@ -318,7 +320,9 @@ func InitDesktop(pack modules.Packet) error { if screenshot.NumActiveDisplays() == 0 { if displayBounds.Dx() == 0 || displayBounds.Dy() == 0 { close(desktop.channel) - common.WSConn.SendCallback(modules.Packet{Act: `DESKTOP_QUIT`, Msg: `${i18n|DESKTOP.NO_DISPLAY_FOUND}`}, pack) + data, _ := utils.JSON.Marshal(modules.Packet{Act: `DESKTOP_QUIT`, Msg: `${i18n|DESKTOP.NO_DISPLAY_FOUND}`}) + data = utils.XOR(data, common.WSConn.GetSecret()) + common.WSConn.SendRawData(desktop.rawEvent, data, 20, 03) return errors.New(`${i18n|DESKTOP.NO_DISPLAY_FOUND}`) } } @@ -368,11 +372,13 @@ func KillDesktop(pack modules.Packet) { desktop = val.(*session) } sessions.Remove(uuid) + data, _ := utils.JSON.Marshal(modules.Packet{Act: `DESKTOP_QUIT`, Msg: `${i18n|DESKTOP.SESSION_CLOSED}`}) + data = utils.XOR(data, common.WSConn.GetSecret()) + common.WSConn.SendRawData(desktop.rawEvent, data, 20, 03) desktop.lock.Lock() desktop.escape = true desktop.rawEvent = nil desktop.lock.Unlock() - common.WSConn.SendCallback(modules.Packet{Act: `DESKTOP_QUIT`, Msg: `${i18n|DESKTOP.SESSION_CLOSED}`}, pack) } func GetDesktop(pack modules.Packet) { @@ -404,7 +410,9 @@ func handleDesktop(pack modules.Packet, uuid string, desktop *session) { case msg, ok := <-desktop.channel: // send error info if msg.t == 1 || !ok { - common.WSConn.SendCallback(modules.Packet{Act: `DESKTOP_QUIT`, Msg: msg.info}, pack) + data, _ := utils.JSON.Marshal(modules.Packet{Act: `DESKTOP_QUIT`, Msg: msg.info}) + data = utils.XOR(data, common.WSConn.GetSecret()) + common.WSConn.SendRawData(desktop.rawEvent, data, 20, 03) desktop.escape = true sessions.Remove(uuid) break @@ -428,9 +436,10 @@ func handleDesktop(pack modules.Packet, uuid string, desktop *session) { // set resolution if msg.t == 2 { buf := append([]byte{34, 22, 19, 17, 20, 02}, desktop.rawEvent...) - data := make([]byte, 4) - binary.BigEndian.PutUint16(data[:2], uint16(displayBounds.Dx())) - binary.BigEndian.PutUint16(data[2:], uint16(displayBounds.Dy())) + data := make([]byte, 6) + binary.BigEndian.PutUint16(data[:2], 4) + binary.BigEndian.PutUint16(data[2:4], uint16(displayBounds.Dx())) + binary.BigEndian.PutUint16(data[4:6], uint16(displayBounds.Dy())) buf = append(buf, data...) common.WSConn.SendData(buf) break diff --git a/client/service/terminal/terminal.go b/client/service/terminal/terminal.go index f8ceac6..f7e8462 100644 --- a/client/service/terminal/terminal.go +++ b/client/service/terminal/terminal.go @@ -10,4 +10,19 @@ var ( errDataNotFound = errors.New(`no input found in packet`) errDataInvalid = errors.New(`can not parse data in packet`) errUUIDNotFound = errors.New(`can not find terminal identifier`) -) \ No newline at end of file +) + +// packet explanation: + +// +---------+---------+----------+-------------+------+ +// | magic | op code | event id | data length | data | +// +---------+---------+----------+-------------+------+ +// | 5 bytes | 1 byte | 16 bytes | 2 bytes | - | +// +---------+---------+----------+-------------+------+ + +// magic: +// []byte{34, 22, 19, 17, 21} + +// op code: +// 00: binary packet +// 01: JSON packet diff --git a/client/service/terminal/terminal_others.go b/client/service/terminal/terminal_others.go index ff9b0f0..9b34254 100644 --- a/client/service/terminal/terminal_others.go +++ b/client/service/terminal/terminal_others.go @@ -17,6 +17,7 @@ import ( type terminal struct { escape bool lastPack int64 + rawEvent []byte event string pty *os.File cmd *exec.Cmd @@ -37,29 +38,47 @@ func InitTerminal(pack modules.Packet) error { defaultShell = getTerminal(true) return err } - termSession := &terminal{ + rawEvent, _ := hex.DecodeString(pack.Event) + session := &terminal{ cmd: cmd, pty: ptySession, event: pack.Event, lastPack: utils.Unix, + rawEvent: rawEvent, escape: false, } - terminals.Set(pack.Data[`terminal`].(string), termSession) + terminals.Set(pack.Data[`terminal`].(string), session) go func() { - for !termSession.escape { - buffer := make([]byte, 512) + bufSize := 1024 + for !session.escape { + buffer := make([]byte, bufSize) n, err := ptySession.Read(buffer) buffer = buffer[:n] - common.WSConn.SendCallback(modules.Packet{Act: `TERMINAL_OUTPUT`, Data: map[string]any{ - `output`: hex.EncodeToString(buffer), - }}, pack) - termSession.lastPack = utils.Unix + + // if output is larger than 1KB, then send binary data + if n > 1024 { + if bufSize < 32768 { + bufSize *= 2 + } + common.WSConn.SendRawData(session.rawEvent, buffer, 21, 00) + } else { + bufSize = 1024 + buffer, _ = utils.JSON.Marshal(modules.Packet{Act: `TERMINAL_OUTPUT`, Data: map[string]any{ + `output`: hex.EncodeToString(buffer), + }}) + buffer = utils.XOR(buffer, common.WSConn.GetSecret()) + common.WSConn.SendRawData(session.rawEvent, buffer, 21, 01) + } + + session.lastPack = utils.Unix if err != nil { - if !termSession.escape { - termSession.escape = true - doKillTerminal(termSession) + if !session.escape { + session.escape = true + doKillTerminal(session) } - common.WSConn.SendCallback(modules.Packet{Act: `TERMINAL_QUIT`}, pack) + data, _ := utils.JSON.Marshal(modules.Packet{Act: `TERMINAL_QUIT`}) + data = utils.XOR(data, common.WSConn.GetSecret()) + common.WSConn.SendRawData(session.rawEvent, data, 21, 01) break } } @@ -68,77 +87,95 @@ func InitTerminal(pack modules.Packet) error { return nil } -func InputTerminal(pack modules.Packet) error { - val, ok := pack.GetData(`input`, reflect.String) - if !ok { - return errDataNotFound - } - data, err := hex.DecodeString(val.(string)) - if err != nil { - return errDataInvalid +func InputRawTerminal(input []byte, uuid string) { + var session *terminal + + if val, ok := terminals.Get(uuid); ok { + session = val.(*terminal) + } else { + return } + session.pty.Write(input) + session.lastPack = utils.Unix +} + +func InputTerminal(pack modules.Packet) { + var err error + var uuid string + var input []byte + var session *terminal - val, ok = pack.GetData(`terminal`, reflect.String) - if !ok { - return errUUIDNotFound + if val, ok := pack.GetData(`input`, reflect.String); !ok { + return + } else { + if input, err = hex.DecodeString(val.(string)); err != nil { + return + } } - termUUID := val.(string) - val, ok = terminals.Get(termUUID) - if !ok { - common.WSConn.SendCallback(modules.Packet{Act: `TERMINAL_QUIT`, Msg: `${i18n|TERMINAL.SESSION_CLOSED}`}, pack) - return nil + if val, ok := pack.GetData(`terminal`, reflect.String); !ok { + return + } else { + uuid = val.(string) + if val, ok = terminals.Get(uuid); ok { + session = val.(*terminal) + } else { + return + } } - terminal := val.(*terminal) - terminal.pty.Write(data) - terminal.lastPack = utils.Unix - return nil + session.pty.Write(input) + session.lastPack = utils.Unix } -func ResizeTerminal(pack modules.Packet) error { - val, ok := pack.GetData(`width`, reflect.Float64) - if !ok { - return errDataInvalid +func ResizeTerminal(pack modules.Packet) { + var uuid string + var cols, rows uint16 + var session *terminal + if val, ok := pack.GetData(`cols`, reflect.Float64); !ok { + return + } else { + cols = uint16(val.(float64)) } - width := val.(float64) - val, ok = pack.GetData(`height`, reflect.Float64) - if !ok { - return errDataInvalid + if val, ok := pack.GetData(`rows`, reflect.Float64); !ok { + return + } else { + rows = uint16(val.(float64)) } - height := val.(float64) - val, ok = pack.GetData(`terminal`, reflect.String) - if !ok { - return errUUIDNotFound - } - termUUID := val.(string) - val, ok = terminals.Get(termUUID) - if !ok { - common.WSConn.SendCallback(modules.Packet{Act: `TERMINAL_QUIT`, Msg: `${i18n|TERMINAL.SESSION_CLOSED}`}, pack) - return nil + if val, ok := pack.GetData(`terminal`, reflect.String); !ok { + return + } else { + uuid = val.(string) + if val, ok = terminals.Get(uuid); ok { + session = val.(*terminal) + } else { + return + } } - terminal := val.(*terminal) - pty.Setsize(terminal.pty, &pty.Winsize{ - Rows: uint16(height), - Cols: uint16(width), + pty.Setsize(session.pty, &pty.Winsize{ + Cols: cols, + Rows: rows, }) - return nil } -func KillTerminal(pack modules.Packet) error { - val, ok := pack.GetData(`terminal`, reflect.String) - if !ok { - return errUUIDNotFound - } - termUUID := val.(string) - val, ok = terminals.Get(termUUID) - if !ok { - common.WSConn.SendCallback(modules.Packet{Act: `TERMINAL_QUIT`, Msg: `${i18n|TERMINAL.SESSION_CLOSED}`}, pack) - return nil +func KillTerminal(pack modules.Packet) { + var uuid string + var session *terminal + if val, ok := pack.GetData(`terminal`, reflect.String); !ok { + return + } else { + uuid = val.(string) } - terminal := val.(*terminal) - terminals.Remove(termUUID) - doKillTerminal(terminal) - return nil + if val, ok := terminals.Get(uuid); !ok { + return + } else { + session = val.(*terminal) + } + terminals.Remove(uuid) + data, _ := utils.JSON.Marshal(modules.Packet{Act: `TERMINAL_QUIT`, Msg: `${i18n|TERMINAL.SESSION_CLOSED}`}) + data = utils.XOR(data, common.WSConn.GetSecret()) + common.WSConn.SendRawData(session.rawEvent, data, 21, 01) + session.escape = true + session.rawEvent = nil } func PingTerminal(pack modules.Packet) { diff --git a/client/service/terminal/terminal_windows.go b/client/service/terminal/terminal_windows.go index 0596d82..ec383cb 100644 --- a/client/service/terminal/terminal_windows.go +++ b/client/service/terminal/terminal_windows.go @@ -14,8 +14,9 @@ import ( type terminal struct { lastPack int64 + rawEvent []byte + escape bool event string - stop bool cmd *exec.Cmd stdout *io.ReadCloser stderr *io.ReadCloser @@ -50,29 +51,46 @@ func InitTerminal(pack modules.Packet) error { if err != nil { return err } - termSession := &terminal{ + rawEvent, _ := hex.DecodeString(pack.Event) + session := &terminal{ cmd: cmd, - stop: false, event: pack.Event, + escape: false, stdout: &stdout, stderr: &stderr, stdin: &stdin, + rawEvent: rawEvent, lastPack: utils.Unix, } readSender := func(rc io.ReadCloser) { - for !termSession.stop { - buffer := make([]byte, 512) + bufSize := 1024 + for !session.escape { + buffer := make([]byte, 1024) n, err := rc.Read(buffer) buffer = buffer[:n] - common.WSConn.SendCallback(modules.Packet{Act: `TERMINAL_OUTPUT`, Data: map[string]any{ - `output`: hex.EncodeToString(buffer), - }}, pack) - termSession.lastPack = utils.Unix + // if output is larger than 1KB, then send binary data + if n > 1024 { + if bufSize < 32768 { + bufSize *= 2 + } + common.WSConn.SendRawData(session.rawEvent, buffer, 21, 00) + } else { + bufSize = 1024 + buffer, _ = utils.JSON.Marshal(modules.Packet{Act: `TERMINAL_OUTPUT`, Data: map[string]any{ + `output`: hex.EncodeToString(buffer), + }}) + buffer = utils.XOR(buffer, common.WSConn.GetSecret()) + common.WSConn.SendRawData(session.rawEvent, buffer, 21, 01) + } + + session.lastPack = utils.Unix if err != nil { - termSession.stop = true - common.WSConn.SendCallback(modules.Packet{Act: `TERMINAL_QUIT`}, pack) + session.escape = true + data, _ := utils.JSON.Marshal(modules.Packet{Act: `TERMINAL_QUIT`}) + data = utils.XOR(data, common.WSConn.GetSecret()) + common.WSConn.SendRawData(session.rawEvent, data, 21, 01) break } } @@ -82,73 +100,90 @@ func InitTerminal(pack modules.Packet) error { err = cmd.Start() if err != nil { - termSession.stop = true + session.escape = true return err } - terminals.Set(pack.Data[`terminal`].(string), termSession) + terminals.Set(pack.Data[`terminal`].(string), session) return nil } -func InputTerminal(pack modules.Packet) error { - val, ok := pack.GetData(`input`, reflect.String) - if !ok { - return errDataNotFound - } - data, err := hex.DecodeString(val.(string)) - if err != nil { - return errDataInvalid +func InputRawTerminal(input []byte, uuid string) { + var session *terminal + + if val, ok := terminals.Get(uuid); ok { + session = val.(*terminal) + } else { + return } + (*session.stdin).Write(input) + session.lastPack = utils.Unix +} + +func InputTerminal(pack modules.Packet) { + var err error + var uuid string + var input []byte + var session *terminal - val, ok = pack.GetData(`terminal`, reflect.String) - if !ok { - return errUUIDNotFound + if val, ok := pack.GetData(`input`, reflect.String); !ok { + return + } else { + if input, err = hex.DecodeString(val.(string)); err != nil { + return + } } - termUUID := val.(string) - val, ok = terminals.Get(termUUID) - if !ok { - common.WSConn.SendCallback(modules.Packet{Act: `TERMINAL_QUIT`, Msg: `${i18n|TERMINAL.SESSION_CLOSED}`}, pack) - return nil + if val, ok := pack.GetData(`terminal`, reflect.String); !ok { + return + } else { + uuid = val.(string) + if val, ok = terminals.Get(uuid); ok { + session = val.(*terminal) + } else { + return + } } - terminal := val.(*terminal) - (*terminal.stdin).Write(data) - terminal.lastPack = utils.Unix - return nil + (*session.stdin).Write(input) + session.lastPack = utils.Unix } func ResizeTerminal(pack modules.Packet) error { return nil } -func KillTerminal(pack modules.Packet) error { - val, ok := pack.GetData(`terminal`, reflect.String) - if !ok { - return errUUIDNotFound - } - termUUID := val.(string) - val, ok = terminals.Get(termUUID) - if !ok { - common.WSConn.SendCallback(modules.Packet{Act: `TERMINAL_QUIT`, Msg: `${i18n|TERMINAL.SESSION_CLOSED}`}, pack) - return nil +func KillTerminal(pack modules.Packet) { + var uuid string + var session *terminal + if val, ok := pack.GetData(`terminal`, reflect.String); !ok { + return + } else { + uuid = val.(string) } - terminal := val.(*terminal) - terminals.Remove(termUUID) - doKillTerminal(terminal) - return nil + if val, ok := terminals.Get(uuid); !ok { + return + } else { + session = val.(*terminal) + } + terminals.Remove(uuid) + data, _ := utils.JSON.Marshal(modules.Packet{Act: `TERMINAL_QUIT`, Msg: `${i18n|TERMINAL.SESSION_CLOSED}`}) + data = utils.XOR(data, common.WSConn.GetSecret()) + common.WSConn.SendRawData(session.rawEvent, data, 21, 01) + session.escape = true + session.rawEvent = nil } func PingTerminal(pack modules.Packet) { - var termUUID string - var termSession *terminal + var uuid string + var session *terminal if val, ok := pack.GetData(`terminal`, reflect.String); !ok { return } else { - termUUID = val.(string) + uuid = val.(string) } - if val, ok := terminals.Get(termUUID); !ok { + if val, ok := terminals.Get(uuid); !ok { return } else { - termSession = val.(*terminal) - termSession.lastPack = utils.Unix + session = val.(*terminal) + session.lastPack = utils.Unix } } diff --git a/licenses/concurrent-map.LICENSE b/licenses/concurrent-map.LICENSE new file mode 100644 index 0000000..ea2fec0 --- /dev/null +++ b/licenses/concurrent-map.LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014 streamrail + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/licenses/melody.LICENSE b/licenses/melody.LICENSE new file mode 100644 index 0000000..4ae857e --- /dev/null +++ b/licenses/melody.LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2015 Ola Holmström. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/zmodemjs.LICENSE b/licenses/zmodemjs.LICENSE new file mode 100644 index 0000000..8dada3e --- /dev/null +++ b/licenses/zmodemjs.LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. diff --git a/scripts/release.js b/scripts/release.js new file mode 100644 index 0000000..c3bf357 --- /dev/null +++ b/scripts/release.js @@ -0,0 +1,27 @@ +const process = require("process"); +const fs = require("fs"); + +let changelogs = fs.readFileSync("CHANGELOG.md", "utf-8").toString().split("\n\n\n\n"); +if (changelogs.length === 0) { + console.error("Failed to read CHANGELOG.md."); + process.exit(1); +} +let generated = false; +for (let i = 0; i < changelogs.length; i++) { + let thisNotes = changelogs[i].split("\n"); + if (thisNotes.length === 0) { + continue; + } + if (!thisNotes.shift().endsWith(process.argv[2])) { + continue + } + thisNotes.shift(); + fs.writeFileSync("CHANGELOG.md", thisNotes.join("\n")); + generated = true; + break +} +if (!generated) { + console.log(`Failed to find version ${process.argv[2]} in current changelog.`); + process.exit(1); +} +console.log("New CHANGELOG.md generated."); diff --git a/server/handler/desktop/desktop.go b/server/handler/desktop/desktop.go index 7632ab1..1bb56d0 100644 --- a/server/handler/desktop/desktop.go +++ b/server/handler/desktop/desktop.go @@ -62,20 +62,29 @@ func InitDesktop(ctx *gin.Context) { }) } -// desktopEventWrapper returns a eventCb function that will be called when -// device need to send a packet to browser +// desktopEventWrapper returns a eventCallback function that will +// be called when device need to send a packet to browser terminal func desktopEventWrapper(desktop *desktop) common.EventCallback { return func(pack modules.Packet, device *melody.Session) { - if len(pack.Act) == 0 { - if pack.Data == nil { + if pack.Act == `RAW_DATA_ARRIVE` && pack.Data != nil { + data := *pack.Data[`data`].(*[]byte) + if data[5] == 00 || data[5] == 01 || data[5] == 02 { + desktop.srcConn.WriteBinary(data) return } - if data, ok := pack.Data[`data`]; ok { - desktop.srcConn.WriteBinary(*data.(*[]byte)) + + if data[5] != 03 { + return + } + data = data[8:] + data = utility.SimpleDecrypt(data, device) + if utils.JSON.Unmarshal(data, &pack) != nil { + return } - return } - if pack.Act == `DESKTOP_INIT` { + + switch pack.Act { + case `DESKTOP_INIT`: if pack.Code != 0 { msg := `${i18n|DESKTOP.CREATE_SESSION_FAILED}` if len(pack.Msg) > 0 { @@ -94,9 +103,7 @@ func desktopEventWrapper(desktop *desktop) common.EventCallback { `deviceConn`: desktop.deviceConn, }) } - return - } - if pack.Act == `DESKTOP_QUIT` { + case `DESKTOP_QUIT`: msg := `${i18n|DESKTOP.SESSION_CLOSED}` if len(pack.Msg) > 0 { msg = pack.Msg @@ -107,7 +114,6 @@ func desktopEventWrapper(desktop *desktop) common.EventCallback { common.Info(desktop.srcConn, `DESKTOP_QUIT`, `success`, ``, map[string]any{ `deviceConn`: desktop.deviceConn, }) - return } } } @@ -150,31 +156,39 @@ func onDesktopConnect(session *melody.Session) { func onDesktopMessage(session *melody.Session, data []byte) { var pack modules.Packet - data, ok := utility.SimpleDecrypt(data, session) - if !(ok && utils.JSON.Unmarshal(data, &pack) == nil) { - if val, ok := session.Get(`Desktop`); !ok { - desktop := val.(*desktop) - common.SendPack(modules.Packet{Act: `DESKTOP_KILL`, Data: gin.H{ - `desktop`: desktop.uuid, - }, Event: desktop.uuid}, desktop.deviceConn) - } + val, ok := session.Get(`Desktop`) + if !ok { + return + } + desktop := val.(*desktop) + + service, op, isBinary := utils.CheckBinaryPack(data) + if !isBinary || service != 20 { sendPack(modules.Packet{Code: -1}, session) session.Close() return } - val, ok := session.Get(`Desktop`) - if !ok { + if op != 03 { + sendPack(modules.Packet{Code: -1}, session) + session.Close() + return + } + + data = utility.SimpleDecrypt(data[8:], session) + if utils.JSON.Unmarshal(data, &pack) != nil { + sendPack(modules.Packet{Code: -1}, session) + session.Close() return } - desktop := val.(*desktop) session.Set(`LastPack`, utils.Unix) - if pack.Act == `DESKTOP_PING` { + + switch pack.Act { + case `DESKTOP_PING`: common.SendPack(modules.Packet{Act: `DESKTOP_PING`, Data: gin.H{ `desktop`: desktop.uuid, }, Event: desktop.uuid}, desktop.deviceConn) return - } - if pack.Act == `DESKTOP_KILL` { + case `DESKTOP_KILL`: common.Info(desktop.srcConn, `DESKTOP_KILL`, `success`, ``, map[string]any{ `deviceConn`: desktop.deviceConn, }) @@ -182,8 +196,7 @@ func onDesktopMessage(session *melody.Session, data []byte) { `desktop`: desktop.uuid, }, Event: desktop.uuid}, desktop.deviceConn) return - } - if pack.Act == `DESKTOP_SHOT` { + case `DESKTOP_SHOT`: common.SendPack(modules.Packet{Act: `DESKTOP_SHOT`, Data: gin.H{ `desktop`: desktop.uuid, }, Event: desktop.uuid}, desktop.deviceConn) @@ -218,11 +231,8 @@ func sendPack(pack modules.Packet, session *melody.Session) bool { if err != nil { return false } - data, ok := utility.SimpleEncrypt(data, session) - if !ok { - return false - } - err = session.WriteBinary(append([]byte{00, 22, 34, 19, 20, 03}, data...)) + data = utility.SimpleEncrypt(data, session) + err = session.WriteBinary(append([]byte{34, 22, 19, 17, 20, 03}, data...)) return err == nil } diff --git a/server/handler/terminal/terminal.go b/server/handler/terminal/terminal.go index ef12f62..037738a 100644 --- a/server/handler/terminal/terminal.go +++ b/server/handler/terminal/terminal.go @@ -22,6 +22,7 @@ type terminal struct { var terminalSessions = melody.New() func init() { + terminalSessions.Config.MaxMessageSize = common.MaxMessageSize terminalSessions.HandleConnect(onTerminalConnect) terminalSessions.HandleMessage(onTerminalMessage) terminalSessions.HandleMessageBinary(onTerminalMessage) @@ -62,11 +63,29 @@ func InitTerminal(ctx *gin.Context) { }) } -// terminalEventWrapper returns a eventCb function that will be called when -// device need to send a packet to browser terminal +// terminalEventWrapper returns a eventCallback function that will +// be called when device need to send a packet to browser terminal func terminalEventWrapper(terminal *terminal) common.EventCallback { return func(pack modules.Packet, device *melody.Session) { - if pack.Act == `TERMINAL_INIT` { + if pack.Act == `RAW_DATA_ARRIVE` && pack.Data != nil { + data := *pack.Data[`data`].(*[]byte) + if data[5] == 00 { + terminal.session.WriteBinary(data) + return + } + + if data[5] != 01 { + return + } + data = data[8:] + data = utility.SimpleDecrypt(data, device) + if utils.JSON.Unmarshal(data, &pack) != nil { + return + } + } + + switch pack.Act { + case `TERMINAL_INIT`: if pack.Code != 0 { msg := `${i18n|TERMINAL.CREATE_SESSION_FAILED}` if len(pack.Msg) > 0 { @@ -74,7 +93,7 @@ func terminalEventWrapper(terminal *terminal) common.EventCallback { } else { msg += `${i18n|COMMON.UNKNOWN_ERROR}` } - sendPack(modules.Packet{Act: `WARN`, Msg: msg}, terminal.session) + sendPack(modules.Packet{Act: `QUIT`, Msg: msg}, terminal.session) common.RemoveEvent(terminal.uuid) terminal.session.Close() common.Warn(terminal.session, `TERMINAL_INIT`, `fail`, msg, map[string]any{ @@ -85,22 +104,18 @@ func terminalEventWrapper(terminal *terminal) common.EventCallback { `deviceConn`: terminal.deviceConn, }) } - return - } - if pack.Act == `TERMINAL_QUIT` { + case `TERMINAL_QUIT`: msg := `${i18n|TERMINAL.SESSION_CLOSED}` if len(pack.Msg) > 0 { msg = pack.Msg } - sendPack(modules.Packet{Act: `WARN`, Msg: msg}, terminal.session) + sendPack(modules.Packet{Act: `QUIT`, Msg: msg}, terminal.session) common.RemoveEvent(terminal.uuid) terminal.session.Close() common.Info(terminal.session, `TERMINAL_QUIT`, ``, msg, map[string]any{ `deviceConn`: terminal.deviceConn, }) - return - } - if pack.Act == `TERMINAL_OUTPUT` { + case `TERMINAL_OUTPUT`: if pack.Data == nil { return } @@ -132,18 +147,18 @@ func onTerminalConnect(session *melody.Session) { session.Close() return } - termUUID := utils.GetStrUUID() + uuid := utils.GetStrUUID() terminal := &terminal{ - uuid: termUUID, + uuid: uuid, device: device.(string), session: session, deviceConn: deviceConn, } session.Set(`Terminal`, terminal) - common.AddEvent(terminalEventWrapper(terminal), connUUID, termUUID) + common.AddEvent(terminalEventWrapper(terminal), connUUID, uuid) common.SendPack(modules.Packet{Act: `TERMINAL_INIT`, Data: gin.H{ - `terminal`: termUUID, - }, Event: termUUID}, deviceConn) + `terminal`: uuid, + }, Event: uuid}, deviceConn) common.Info(terminal.session, `TERMINAL_CONN`, `success`, ``, map[string]any{ `deviceConn`: terminal.deviceConn, }) @@ -151,19 +166,43 @@ func onTerminalConnect(session *melody.Session) { func onTerminalMessage(session *melody.Session, data []byte) { var pack modules.Packet - data, ok := utility.SimpleDecrypt(data, session) - if !(ok && utils.JSON.Unmarshal(data, &pack) == nil) { + val, ok := session.Get(`Terminal`) + if !ok { + return + } + terminal := val.(*terminal) + + service, op, isBinary := utils.CheckBinaryPack(data) + if !isBinary || service != 21 { sendPack(modules.Packet{Code: -1}, session) session.Close() return } - val, ok := session.Get(`Terminal`) - if !ok { + if op == 00 { + session.Set(`LastPack`, utils.Unix) + rawEvent, _ := hex.DecodeString(terminal.uuid) + data = append(data, rawEvent...) + copy(data[22:], data[6:]) + copy(data[6:], rawEvent) + terminal.deviceConn.WriteBinary(data) + return + } + if op != 01 { + sendPack(modules.Packet{Code: -1}, session) + session.Close() + return + } + + data = utility.SimpleDecrypt(data[8:], session) + if utils.JSON.Unmarshal(data, &pack) != nil { + sendPack(modules.Packet{Code: -1}, session) + session.Close() return } - terminal := val.(*terminal) session.Set(`LastPack`, utils.Unix) - if pack.Act == `TERMINAL_INPUT` { + + switch pack.Act { + case `TERMINAL_INPUT`: if pack.Data == nil { return } @@ -179,26 +218,21 @@ func onTerminalMessage(session *melody.Session, data []byte) { }, Event: terminal.uuid}, terminal.deviceConn) } return - } - if pack.Act == `TERMINAL_RESIZE` { + case `TERMINAL_RESIZE`: if pack.Data == nil { return } - if width, ok := pack.Data[`width`]; ok { - if height, ok := pack.Data[`height`]; ok { + if cols, ok := pack.Data[`cols`]; ok { + if rows, ok := pack.Data[`rows`]; ok { common.SendPack(modules.Packet{Act: `TERMINAL_RESIZE`, Data: gin.H{ - `width`: width, - `height`: height, + `cols`: cols, + `rows`: rows, `terminal`: terminal.uuid, }, Event: terminal.uuid}, terminal.deviceConn) } } return - } - if pack.Act == `TERMINAL_KILL` { - if pack.Data == nil { - return - } + case `TERMINAL_KILL`: common.Info(terminal.session, `TERMINAL_KILL`, `success`, ``, map[string]any{ `deviceConn`: terminal.deviceConn, }) @@ -206,11 +240,7 @@ func onTerminalMessage(session *melody.Session, data []byte) { `terminal`: terminal.uuid, }, Event: terminal.uuid}, terminal.deviceConn) return - } - if pack.Act == `PING` { - if pack.Data == nil { - return - } + case `PING`: common.SendPack(modules.Packet{Act: `TERMINAL_PING`, Data: gin.H{ `terminal`: terminal.uuid, }, Event: terminal.uuid}, terminal.deviceConn) @@ -245,10 +275,7 @@ func sendPack(pack modules.Packet, session *melody.Session) bool { if err != nil { return false } - data, ok := utility.SimpleEncrypt(data, session) - if !ok { - return false - } + data = utility.SimpleEncrypt(data, session) err = session.WriteBinary(data) return err == nil } diff --git a/server/handler/utility/utility.go b/server/handler/utility/utility.go index 7119e18..0e652d8 100644 --- a/server/handler/utility/utility.go +++ b/server/handler/utility/utility.go @@ -8,8 +8,6 @@ import ( "Spark/utils/melody" "bytes" "context" - "crypto/aes" - "crypto/cipher" "fmt" "github.com/gin-gonic/gin" "net/http" @@ -331,36 +329,22 @@ func CallDevice(ctx *gin.Context) { } } -func SimpleEncrypt(data []byte, session *melody.Session) ([]byte, bool) { +func SimpleEncrypt(data []byte, session *melody.Session) []byte { temp, ok := session.Get(`Secret`) if !ok { - return nil, false + return nil } secret := temp.([]byte) - block, err := aes.NewCipher(secret) - if err != nil { - return nil, false - } - stream := cipher.NewCTR(block, secret) - encBuffer := make([]byte, len(data)) - stream.XORKeyStream(encBuffer, data) - return encBuffer, true + return utils.XOR(data, secret) } -func SimpleDecrypt(data []byte, session *melody.Session) ([]byte, bool) { +func SimpleDecrypt(data []byte, session *melody.Session) []byte { temp, ok := session.Get(`Secret`) if !ok { - return nil, false + return nil } secret := temp.([]byte) - block, err := aes.NewCipher(secret) - if err != nil { - return nil, false - } - stream := cipher.NewCTR(block, secret) - decBuffer := make([]byte, len(data)) - stream.XORKeyStream(decBuffer, data) - return decBuffer, true + return utils.XOR(data, secret) } func WSHealthCheck(container *melody.Melody, sender Sender) { diff --git a/server/main.go b/server/main.go index f294e39..7d4b7ab 100644 --- a/server/main.go +++ b/server/main.go @@ -158,20 +158,38 @@ func wsOnMessage(session *melody.Session, _ []byte) { func wsOnMessageBinary(session *melody.Session, data []byte) { var pack modules.Packet - { - dataLen := len(data) - if dataLen >= 22 { - if bytes.Equal(data[:5], []byte{34, 22, 19, 17, 20}) { - event := hex.EncodeToString(data[6:22]) - copy(data[6:], data[22:]) - common.CallEvent(modules.Packet{ - Event: event, - Data: gin.H{ - `data`: utils.GetSlicePrefix(&data, dataLen-16), - }, - }, session) - return + dataLen := len(data) + if dataLen > 24 { + if service, op, isBinary := utils.CheckBinaryPack(data); isBinary { + switch service { + case 20: + switch op { + case 00, 01, 02, 03: + event := hex.EncodeToString(data[6:22]) + copy(data[6:], data[22:]) + common.CallEvent(modules.Packet{ + Act: `RAW_DATA_ARRIVE`, + Event: event, + Data: gin.H{ + `data`: utils.GetSlicePrefix(&data, dataLen-16), + }, + }, session) + } + case 21: + switch op { + case 00, 01: + event := hex.EncodeToString(data[6:22]) + copy(data[6:], data[22:]) + common.CallEvent(modules.Packet{ + Act: `RAW_DATA_ARRIVE`, + Event: event, + Data: gin.H{ + `data`: utils.GetSlicePrefix(&data, dataLen-16), + }, + }, session) + } } + return } } diff --git a/utils/utils.go b/utils/utils.go index 42d1985..c49fb3b 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -41,6 +41,16 @@ func Max[T int | int32 | int64 | uint | uint32 | uint64 | float32 | float64](a, return b } +func XOR(data []byte, key []byte) []byte { + if len(key) == 0 { + return data + } + for i := 0; i < len(data); i++ { + data[i] = data[i] ^ key[i%len(key)] + } + return data +} + func GenRandByte(n int) []byte { secBuffer := make([]byte, n) rand.Reader.Read(secBuffer) @@ -185,3 +195,14 @@ func GetSliceChunk[T any](data *[]T, start, end int) *[]T { Cap: end - start, })) } + +func CheckBinaryPack(data []byte) (byte, byte, bool) { + if len(data) >= 8 { + if bytes.Equal(data[:4], []byte{34, 22, 19, 17}) { + if data[4] == 20 || data[4] == 21 { + return data[4], data[5], true + } + } + } + return 0, 0, false +} diff --git a/web/package-lock.json b/web/package-lock.json index 97f9190..7c5b172 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -14,9 +14,9 @@ "@ant-design/pro-layout": "^6.23.0", "@ant-design/pro-table": "^2.45.0", "ace-builds": "^1.5.3", - "antd": "^4.16.8", + "antd": "^4.23.6", "axios": "^0.26.1", - "crypto-js": "^4.1.1", + "crc-32": "^1.2.2", "dayjs": "^1.10.6", "i18next": "^21.6.15", "lodash": "^4.17.21", @@ -25,13 +25,14 @@ "react-ace": "^10.1.0", "react-dom": "^17.0.2", "react-draggable": "^4.4.5", + "react-markdown": "^8.0.3", "react-router": "^6.2.2", "react-router-dom": "^6.2.2", "virtuallist-antd": "^0.7.4-beta.0", "wcwidth": "^1.0.1", - "xterm": "^4.18.0", - "xterm-addon-fit": "^0.5.0", - "xterm-addon-web-links": "^0.5.1" + "xterm": "^5.0.0", + "xterm-addon-fit": "^0.6.0", + "xterm-addon-web-links": "^0.7.0" }, "devDependencies": { "@babel/core": "^7.17.9", @@ -98,33 +99,69 @@ "integrity": "sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw==" }, "node_modules/@ant-design/pro-card": { - "version": "1.19.4", - "resolved": "https://registry.npmjs.org/@ant-design/pro-card/-/pro-card-1.19.4.tgz", - "integrity": "sha512-pN2xHJ3xpxI0vqc3iOywBKNvqO6x+7IYx01V165ZZboek69Tl8eygr/yGiArIySik/mjZAyP8Ensk8fqxz6WnA==", + "version": "1.20.22", + "resolved": "https://registry.npmjs.org/@ant-design/pro-card/-/pro-card-1.20.22.tgz", + "integrity": "sha512-du4yMSLflfI+SOx7n87FtiPaEmGtWDN4yFC2vfQZQ6rhO0SVAOI2vRPKoXKOZn8Pr9fXVQGo+uPsVXJMZ3WwPg==", "dependencies": { "@ant-design/icons": "^4.2.1", - "@ant-design/pro-utils": "1.39.1", - "@babel/runtime": "^7.16.3", + "@ant-design/pro-utils": "1.45.3", + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", "classnames": "^2.2.6", "omit.js": "^2.0.2", "rc-util": "^5.4.0" }, "peerDependencies": { - "antd": ">=4.18.0", "react": ">=16.9.0" } }, + "node_modules/@ant-design/pro-card/node_modules/@ant-design/pro-provider": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@ant-design/pro-provider/-/pro-provider-1.10.0.tgz", + "integrity": "sha512-gbQtq+Qlnob6aEghiWX/kXEzNhe4eOFlv5Ue2/xsal+22qvot/kFoOB652TD76fMI7vlkoema1pTKsvD5Uji6A==", + "dependencies": { + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", + "rc-util": "^5.0.1", + "swr": "^1.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0" + } + }, + "node_modules/@ant-design/pro-card/node_modules/@ant-design/pro-utils": { + "version": "1.45.3", + "resolved": "https://registry.npmjs.org/@ant-design/pro-utils/-/pro-utils-1.45.3.tgz", + "integrity": "sha512-W2qtyckdkHTWGVXfFfqb9s/ahq3o4GlIZC3+WDiGUgqJTsUkwY69yV67E2ZfAro1XRXblUzbvxIv96M7bEAfFg==", + "dependencies": { + "@ant-design/icons": "^4.3.0", + "@ant-design/pro-provider": "1.10.0", + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", + "classnames": "^2.2.6", + "moment": "^2.27.0", + "rc-util": "^5.0.6", + "react-sortable-hoc": "^2.0.0", + "swr": "^1.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, "node_modules/@ant-design/pro-field": { - "version": "1.34.4", - "resolved": "https://registry.npmjs.org/@ant-design/pro-field/-/pro-field-1.34.4.tgz", - "integrity": "sha512-PPKihq+Gw4aV456ChVXBY3u6UwO835SxACo/u2zIB+J1k0mgn3kB6HjYAbgasrVtm6cFC4Q5I+otLO6H8G/8Wg==", + "version": "1.36.7", + "resolved": "https://registry.npmjs.org/@ant-design/pro-field/-/pro-field-1.36.7.tgz", + "integrity": "sha512-N5DGitBT2o5UC5lR8M6CQOhKsTMqhzggR6Q0xC2Uj50eUmy5A2uFDnsCjlaSgprocpIK0/zvTU02V9yE62SHSw==", "dependencies": { "@ant-design/icons": "^4.2.1", - "@ant-design/pro-provider": "1.6.3", - "@ant-design/pro-utils": "1.39.1", - "@babel/runtime": "^7.16.3", + "@ant-design/pro-provider": "1.10.0", + "@ant-design/pro-utils": "1.45.3", + "@babel/runtime": "^7.18.0", "@chenshuai2144/sketch-color": "^1.0.8", + "antd": "^4.20.0 ", "classnames": "^2.2.6", + "lodash.omit": "^4.5.0", "lodash.tonumber": "^4.0.3", "moment": "^2.27.0", "omit.js": "^2.0.2", @@ -132,36 +169,103 @@ "swr": "^1.2.0" }, "peerDependencies": { - "antd": ">=4.18.0", "react": ">=16.9.0" } }, + "node_modules/@ant-design/pro-field/node_modules/@ant-design/pro-provider": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@ant-design/pro-provider/-/pro-provider-1.10.0.tgz", + "integrity": "sha512-gbQtq+Qlnob6aEghiWX/kXEzNhe4eOFlv5Ue2/xsal+22qvot/kFoOB652TD76fMI7vlkoema1pTKsvD5Uji6A==", + "dependencies": { + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", + "rc-util": "^5.0.1", + "swr": "^1.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0" + } + }, + "node_modules/@ant-design/pro-field/node_modules/@ant-design/pro-utils": { + "version": "1.45.3", + "resolved": "https://registry.npmjs.org/@ant-design/pro-utils/-/pro-utils-1.45.3.tgz", + "integrity": "sha512-W2qtyckdkHTWGVXfFfqb9s/ahq3o4GlIZC3+WDiGUgqJTsUkwY69yV67E2ZfAro1XRXblUzbvxIv96M7bEAfFg==", + "dependencies": { + "@ant-design/icons": "^4.3.0", + "@ant-design/pro-provider": "1.10.0", + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", + "classnames": "^2.2.6", + "moment": "^2.27.0", + "rc-util": "^5.0.6", + "react-sortable-hoc": "^2.0.0", + "swr": "^1.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, "node_modules/@ant-design/pro-form": { - "version": "1.64.0", - "resolved": "https://registry.npmjs.org/@ant-design/pro-form/-/pro-form-1.64.0.tgz", - "integrity": "sha512-PDGRATaN/GbiSD+dA3dMuhRtB/2rXa2Ztm59UOneugYYzygRkVeEuHlxv/q1zahvJOfVzLykVZBnzsK8J7wTyw==", + "version": "1.74.7", + "resolved": "https://registry.npmjs.org/@ant-design/pro-form/-/pro-form-1.74.7.tgz", + "integrity": "sha512-3r6DdAkvsjN0lpVnbpAbtj5n+Od+IeLE6Z6DKPChobtwYJX5XyR8fWWOnyR43W8qbGTpXMxDwO9IP3VRY7VdMQ==", "dependencies": { "@ant-design/icons": "^4.2.1", - "@ant-design/pro-field": "1.34.4", - "@ant-design/pro-provider": "1.6.3", - "@ant-design/pro-utils": "1.39.1", - "@babel/runtime": "^7.16.3", + "@ant-design/pro-field": "1.36.7", + "@ant-design/pro-provider": "1.10.0", + "@ant-design/pro-utils": "1.45.3", + "@babel/runtime": "^7.18.0", "@umijs/use-params": "^1.0.9", + "antd": "^4.20.0 ", "classnames": "^2.2.6", - "lodash": "^4.17.21", + "lodash.merge": "^4.6.2", "omit.js": "^2.0.2", "rc-resize-observer": "^1.1.0", "rc-util": "^5.0.6", "use-json-comparison": "^1.0.5", - "use-media-antd-query": "^1.0.6" + "use-media-antd-query": "^1.1.0" }, "peerDependencies": { - "antd": ">=4.18.0", "rc-field-form": "^1.22.0", "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, + "node_modules/@ant-design/pro-form/node_modules/@ant-design/pro-provider": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@ant-design/pro-provider/-/pro-provider-1.10.0.tgz", + "integrity": "sha512-gbQtq+Qlnob6aEghiWX/kXEzNhe4eOFlv5Ue2/xsal+22qvot/kFoOB652TD76fMI7vlkoema1pTKsvD5Uji6A==", + "dependencies": { + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", + "rc-util": "^5.0.1", + "swr": "^1.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0" + } + }, + "node_modules/@ant-design/pro-form/node_modules/@ant-design/pro-utils": { + "version": "1.45.3", + "resolved": "https://registry.npmjs.org/@ant-design/pro-utils/-/pro-utils-1.45.3.tgz", + "integrity": "sha512-W2qtyckdkHTWGVXfFfqb9s/ahq3o4GlIZC3+WDiGUgqJTsUkwY69yV67E2ZfAro1XRXblUzbvxIv96M7bEAfFg==", + "dependencies": { + "@ant-design/icons": "^4.3.0", + "@ant-design/pro-provider": "1.10.0", + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", + "classnames": "^2.2.6", + "moment": "^2.27.0", + "rc-util": "^5.0.6", + "react-sortable-hoc": "^2.0.0", + "swr": "^1.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, "node_modules/@ant-design/pro-layout": { "version": "6.35.0", "resolved": "https://registry.npmjs.org/@ant-design/pro-layout/-/pro-layout-6.35.0.tgz", @@ -206,17 +310,18 @@ } }, "node_modules/@ant-design/pro-table": { - "version": "2.71.6", - "resolved": "https://registry.npmjs.org/@ant-design/pro-table/-/pro-table-2.71.6.tgz", - "integrity": "sha512-GfeNY/hgMzWSYOrfQ4fgmw4T46FeSroUvDmV8GOzNd8P0HlfukDlztDXfzjVdrez4g9Y0Ub8uF0EIMjFETgL7g==", + "version": "2.80.8", + "resolved": "https://registry.npmjs.org/@ant-design/pro-table/-/pro-table-2.80.8.tgz", + "integrity": "sha512-QPrGJJpXk8va/sUMlBYXIxNenc0OMHK+LKKLKOmh1hoA+a6/a75Tk+VaoncLGZZ99qXDQwMLlRZXMGDhrtCGgA==", "dependencies": { "@ant-design/icons": "^4.1.0", - "@ant-design/pro-card": "1.19.4", - "@ant-design/pro-field": "1.34.4", - "@ant-design/pro-form": "1.64.0", - "@ant-design/pro-provider": "1.6.3", - "@ant-design/pro-utils": "1.39.1", - "@babel/runtime": "^7.16.3", + "@ant-design/pro-card": "1.20.22", + "@ant-design/pro-field": "1.36.7", + "@ant-design/pro-form": "1.74.7", + "@ant-design/pro-provider": "1.10.0", + "@ant-design/pro-utils": "1.45.3", + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", "classnames": "^2.2.6", "moment": "^2.24.0", "omit.js": "^2.0.2", @@ -227,12 +332,45 @@ "use-media-antd-query": "^1.1.0" }, "peerDependencies": { - "antd": ">=4.18.0", "rc-field-form": "^1.22.0", "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, + "node_modules/@ant-design/pro-table/node_modules/@ant-design/pro-provider": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@ant-design/pro-provider/-/pro-provider-1.10.0.tgz", + "integrity": "sha512-gbQtq+Qlnob6aEghiWX/kXEzNhe4eOFlv5Ue2/xsal+22qvot/kFoOB652TD76fMI7vlkoema1pTKsvD5Uji6A==", + "dependencies": { + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", + "rc-util": "^5.0.1", + "swr": "^1.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0" + } + }, + "node_modules/@ant-design/pro-table/node_modules/@ant-design/pro-utils": { + "version": "1.45.3", + "resolved": "https://registry.npmjs.org/@ant-design/pro-utils/-/pro-utils-1.45.3.tgz", + "integrity": "sha512-W2qtyckdkHTWGVXfFfqb9s/ahq3o4GlIZC3+WDiGUgqJTsUkwY69yV67E2ZfAro1XRXblUzbvxIv96M7bEAfFg==", + "dependencies": { + "@ant-design/icons": "^4.3.0", + "@ant-design/pro-provider": "1.10.0", + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", + "classnames": "^2.2.6", + "moment": "^2.27.0", + "rc-util": "^5.0.6", + "react-sortable-hoc": "^2.0.0", + "swr": "^1.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, "node_modules/@ant-design/pro-utils": { "version": "1.39.1", "resolved": "https://registry.npmjs.org/@ant-design/pro-utils/-/pro-utils-1.39.1.tgz", @@ -254,15 +392,15 @@ } }, "node_modules/@ant-design/react-slick": { - "version": "0.28.4", - "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-0.28.4.tgz", - "integrity": "sha512-j9eAHTn7GxbXUFNknJoHS2ceAsqrQi2j8XykjZE1IXCD8kJF+t28EvhBLniDpbOsBk/3kjalnhriTfZcjBHNqg==", + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-0.29.2.tgz", + "integrity": "sha512-kgjtKmkGHa19FW21lHnAfyyH9AAoh35pBdcJ53rHmQ3O+cfFHGHnUbj/HFrRNJ5vIts09FKJVAD8RpaC+RaWfA==", "dependencies": { "@babel/runtime": "^7.10.4", "classnames": "^2.2.5", "json2mq": "^0.2.0", "lodash": "^4.17.21", - "resize-observer-polyfill": "^1.5.0" + "resize-observer-polyfill": "^1.5.1" }, "peerDependencies": { "react": ">=16.9.0" @@ -1852,9 +1990,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", - "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.4.tgz", + "integrity": "sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==", "dependencies": { "regenerator-runtime": "^0.13.4" }, @@ -1939,29 +2077,62 @@ "node": ">=10.0.0" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", "dev": true, "engines": { "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "node_modules/@leichtgewicht/ip-codec": { @@ -2048,6 +2219,14 @@ "@types/node": "*" } }, + "node_modules/@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "dependencies": { + "@types/ms": "*" + } + }, "node_modules/@types/eslint": { "version": "8.4.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", @@ -2107,6 +2286,14 @@ "@types/node": "*" } }, + "node_modules/@types/hast": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", + "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -2128,6 +2315,14 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, + "node_modules/@types/mdast": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", + "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -2140,12 +2335,22 @@ "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", "dev": true }, + "node_modules/@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, "node_modules/@types/node": { "version": "17.0.24", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.24.tgz", "integrity": "sha512-aveCYRQbgTH9Pssp1voEP7HiuWlD2jW2BO56w+bVrJn04i61yh6mRfoKO6hEYQD9vF+W8Chkwc6j1M36uPkx4g==", "dev": true }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, "node_modules/@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", @@ -2158,12 +2363,29 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, + "node_modules/@types/react": { + "version": "18.0.24", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.24.tgz", + "integrity": "sha512-wRJWT6ouziGUy+9uX0aW4YOJxAY0bG6/AOk5AW5QSvZqI7dk6VBIbXvcVgIw/W5Jrl24f77df98GEKTJGOLx7Q==", + "peer": true, + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, "node_modules/@types/retry": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", "dev": true }, + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", + "peer": true + }, "node_modules/@types/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", @@ -2192,6 +2414,11 @@ "@types/node": "*" } }, + "node_modules/@types/unist": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", + "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" + }, "node_modules/@types/ws": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", @@ -2560,52 +2787,53 @@ } }, "node_modules/antd": { - "version": "4.19.5", - "resolved": "https://registry.npmjs.org/antd/-/antd-4.19.5.tgz", - "integrity": "sha512-C4H/VJqlVO5iMvHZyiV27R8SbPs4jsOKCGPhDXIHUry/RnUCbMmVeQaPRfUIxSI1NbqDflsuQfevPtz1svyIlg==", + "version": "4.23.6", + "resolved": "https://registry.npmjs.org/antd/-/antd-4.23.6.tgz", + "integrity": "sha512-AYH57cWBDe1ChtbnvG8i9dpKG4WnjE3AG0zIKpXByFNnxsr4saV6/19ihE8/ImSGpohN4E2zTXmo7R5/MyVRKQ==", "dependencies": { "@ant-design/colors": "^6.0.0", "@ant-design/icons": "^4.7.0", - "@ant-design/react-slick": "~0.28.1", - "@babel/runtime": "^7.12.5", + "@ant-design/react-slick": "~0.29.1", + "@babel/runtime": "^7.18.3", "@ctrl/tinycolor": "^3.4.0", "classnames": "^2.2.6", "copy-to-clipboard": "^3.2.0", "lodash": "^4.17.21", "memoize-one": "^6.0.0", - "moment": "^2.25.3", - "rc-cascader": "~3.2.1", + "moment": "^2.29.2", + "rc-cascader": "~3.7.0", "rc-checkbox": "~2.3.0", - "rc-collapse": "~3.1.0", - "rc-dialog": "~8.6.0", - "rc-drawer": "~4.4.2", - "rc-dropdown": "~3.3.2", - "rc-field-form": "~1.25.0", - "rc-image": "~5.2.5", - "rc-input": "~0.0.1-alpha.5", - "rc-input-number": "~7.3.0", - "rc-mentions": "~1.6.1", - "rc-menu": "~9.3.2", - "rc-motion": "^2.4.4", - "rc-notification": "~4.5.7", - "rc-pagination": "~3.1.9", - "rc-picker": "~2.6.4", - "rc-progress": "~3.2.1", + "rc-collapse": "~3.3.0", + "rc-dialog": "~8.9.0", + "rc-drawer": "~5.1.0", + "rc-dropdown": "~4.0.0", + "rc-field-form": "~1.27.0", + "rc-image": "~5.7.0", + "rc-input": "~0.1.2", + "rc-input-number": "~7.3.9", + "rc-mentions": "~1.10.0", + "rc-menu": "~9.6.3", + "rc-motion": "^2.6.1", + "rc-notification": "~4.6.0", + "rc-pagination": "~3.1.17", + "rc-picker": "~2.6.11", + "rc-progress": "~3.3.2", "rc-rate": "~2.9.0", "rc-resize-observer": "^1.2.0", - "rc-select": "~14.0.2", - "rc-slider": "~10.0.0-alpha.4", + "rc-segmented": "~2.1.0", + "rc-select": "~14.1.13", + "rc-slider": "~10.0.0", "rc-steps": "~4.1.0", "rc-switch": "~3.2.0", - "rc-table": "~7.23.0", - "rc-tabs": "~11.10.0", - "rc-textarea": "~0.3.0", - "rc-tooltip": "~5.1.1", - "rc-tree": "~5.4.3", - "rc-tree-select": "~5.1.1", + "rc-table": "~7.26.0", + "rc-tabs": "~12.2.0", + "rc-textarea": "~0.4.5", + "rc-tooltip": "~5.2.0", + "rc-tree": "~5.7.0", + "rc-tree-select": "~5.5.0", "rc-trigger": "^5.2.10", "rc-upload": "~4.3.0", - "rc-util": "^5.19.3", + "rc-util": "^5.22.5", "scroll-into-view-if-needed": "^2.2.25" }, "funding": { @@ -2631,23 +2859,6 @@ "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" }, - "node_modules/antd/node_modules/rc-field-form": { - "version": "1.25.2", - "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.25.2.tgz", - "integrity": "sha512-FXGScWibDlwIlKY15T1YOA7VTtMJwqxxXdDjHB56ZNx7wGbE4vK+Fe2zcymyakGZD0ej8NUP5LGr7qBVWaVpUQ==", - "dependencies": { - "@babel/runtime": "^7.8.4", - "async-validator": "^4.0.2", - "rc-util": "^5.8.0" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, "node_modules/anymatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", @@ -2703,9 +2914,9 @@ } }, "node_modules/async-validator": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.0.7.tgz", - "integrity": "sha512-Pj2IR7u8hmUEDOwB++su6baaRi+QvsgajuFB9j95foM1N2gy5HM4z60hfusIO0fBPG5uLAEl6yCJr1jNSVugEQ==" + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==" }, "node_modules/axios": { "version": "0.26.1", @@ -2782,6 +2993,15 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3005,6 +3225,15 @@ "node": ">=4" } }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -3145,6 +3374,15 @@ "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", "dev": true }, + "node_modules/comma-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.2.tgz", + "integrity": "sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/commander": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", @@ -3489,6 +3727,17 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -3503,11 +3752,6 @@ "node": ">= 8" } }, - "node_modules/crypto-js": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", - "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" - }, "node_modules/css-loader": { "version": "6.7.1", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", @@ -3589,10 +3833,16 @@ "node": ">=4" } }, + "node_modules/csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", + "peer": true + }, "node_modules/date-fns": { - "version": "2.28.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", - "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==", + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", "engines": { "node": ">=0.11" }, @@ -3602,15 +3852,14 @@ } }, "node_modules/dayjs": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.1.tgz", - "integrity": "sha512-ER7EjqVAMkRRsxNCC5YqJ9d9VQYuWdGt7aiH2qA5R5wt8ZmWaP2dLUSIK6y/kVzLMlmh1Tvu5xUf4M/wdGJ5KA==" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz", + "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==" }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -3623,6 +3872,18 @@ } } }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/default-gateway": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", @@ -3732,6 +3993,14 @@ "node": ">= 0.6" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, "node_modules/destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", @@ -3744,6 +4013,14 @@ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true }, + "node_modules/diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/diff-match-patch": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", @@ -4164,6 +4441,11 @@ } ] }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -4529,6 +4811,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hast-util-whitespace": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.0.tgz", + "integrity": "sha512-Pkw+xBHuV6xFeJprJe2BBEoDV+AvQySaz3pPDRUs5PNZEMQjpXJJueqrpcHIXxnWTcAGi/UOCgVShlkY6kLoqg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -4829,6 +5120,11 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" + }, "node_modules/interpret": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", @@ -4867,6 +5163,28 @@ "node": ">=8" } }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, "node_modules/is-core-module": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", @@ -5102,7 +5420,7 @@ "node_modules/json2mq": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", - "integrity": "sha1-tje9O6nqvhIsg+lyBIOusQ0skEo=", + "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==", "dependencies": { "string-convert": "^0.2.0" } @@ -5128,6 +5446,14 @@ "node": ">=0.10.0" } }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/klona": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", @@ -5278,6 +5604,11 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, + "node_modules/lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==" + }, "node_modules/lodash.tonumber": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/lodash.tonumber/-/lodash.tonumber-4.0.3.tgz", @@ -5330,6 +5661,72 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mdast-util-definitions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.1.tgz", + "integrity": "sha512-rQ+Gv7mHttxHOBx2dkF4HWTg+EE+UR78ptQWDylzPKaQuVGdG4HIoY3SrS/pCp80nZ04greFvXbVFHT+uf0JVQ==", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "unist-util-visit": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz", + "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "12.2.4", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.2.4.tgz", + "integrity": "sha512-a21xoxSef1l8VhHxS1Dnyioz6grrJkoaCUgGzMD/7dWHvboYX3VW53esRUfB5tgTyz4Yos1n25SPcj35dJqmAg==", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-definitions": "^5.0.0", + "micromark-util-sanitize-uri": "^1.1.0", + "trim-lines": "^3.0.0", + "unist-builder": "^3.0.0", + "unist-util-generated": "^2.0.0", + "unist-util-position": "^4.0.0", + "unist-util-visit": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz", + "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -5386,7 +5783,429 @@ "node": ">= 0.6" } }, - "node_modules/micromatch": { + "node_modules/micromark": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", + "integrity": "sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz", + "integrity": "sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-factory-destination": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz", + "integrity": "sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz", + "integrity": "sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz", + "integrity": "sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz", + "integrity": "sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz", + "integrity": "sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.1.0.tgz", + "integrity": "sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz", + "integrity": "sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz", + "integrity": "sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz", + "integrity": "sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz", + "integrity": "sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz", + "integrity": "sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz", + "integrity": "sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-html-tag-name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.1.0.tgz", + "integrity": "sha512-BKlClMmYROy9UiV03SwNmckkjn8QHVaWkqoAqzivabvdGcwNGMMMH/5szAnywmsTBUzDsU57/mFi0sp4BQO6dA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz", + "integrity": "sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz", + "integrity": "sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.1.0.tgz", + "integrity": "sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz", + "integrity": "sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz", + "integrity": "sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.0.2.tgz", + "integrity": "sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", @@ -5478,18 +6297,25 @@ } }, "node_modules/moment": { - "version": "2.29.2", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.2.tgz", - "integrity": "sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg==", + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", "engines": { "node": "*" } }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "engines": { + "node": ">=4" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/multicast-dns": { "version": "7.2.4", @@ -6093,6 +6919,15 @@ "react-is": "^16.13.1" } }, + "node_modules/property-information": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.1.1.tgz", + "integrity": "sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -6225,15 +7060,15 @@ } }, "node_modules/rc-cascader": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.2.9.tgz", - "integrity": "sha512-Mvkegzf506PD7qc38kg2tGllIBXs5dio3DPg+NER7SiOfCXBCATWYEs0CbUp8JDQgYHoHF0vPvFMYtxFTJuWaw==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.7.0.tgz", + "integrity": "sha512-SFtGpwmYN7RaWEAGTS4Rkc62ZV/qmQGg/tajr/7mfIkleuu8ro9Hlk6J+aA0x1YS4zlaZBtTcSaXM01QMiEV/A==", "dependencies": { "@babel/runtime": "^7.12.5", "array-tree-filter": "^2.1.0", "classnames": "^2.3.1", - "rc-select": "~14.0.0-alpha.23", - "rc-tree": "~5.4.3", + "rc-select": "~14.1.0", + "rc-tree": "~5.7.0", "rc-util": "^5.6.1" }, "peerDependencies": { @@ -6255,9 +7090,9 @@ } }, "node_modules/rc-collapse": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.1.4.tgz", - "integrity": "sha512-WayrhswKMwuJab9xbqFxXTgV0m6X8uOPEO6zm/GJ5YJiJ/wIh/Dd2VtWeI06HYUEnTFv0HNcYv+zWbB+p6OD2A==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.3.1.tgz", + "integrity": "sha512-cOJfcSe3R8vocrF8T+PgaHDrgeA1tX+lwfhwSj60NX9QVRidsILIbRNDLD6nAzmcvVC5PWiIRiR4S1OobxdhCg==", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "2.x", @@ -6271,14 +7106,14 @@ } }, "node_modules/rc-dialog": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-8.6.0.tgz", - "integrity": "sha512-GSbkfqjqxpZC5/zc+8H332+q5l/DKUhpQr0vdX2uDsxo5K0PhvaMEVjyoJUTkZ3+JstEADQji1PVLVb/2bJeOQ==", + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-8.9.0.tgz", + "integrity": "sha512-Cp0tbJnrvPchJfnwIvOMWmJ4yjX3HWFatO6oBFD1jx8QkgsQCR0p8nUWAKdd3seLJhEC39/v56kZaEjwp9muoQ==", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.6", "rc-motion": "^2.3.0", - "rc-util": "^5.6.1" + "rc-util": "^5.21.0" }, "peerDependencies": { "react": ">=16.9.0", @@ -6286,13 +7121,14 @@ } }, "node_modules/rc-drawer": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-4.4.3.tgz", - "integrity": "sha512-FYztwRs3uXnFOIf1hLvFxIQP9MiZJA+0w+Os8dfDh/90X7z/HqP/Yg+noLCIeHEbKln1Tqelv8ymCAN24zPcfQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-5.1.0.tgz", + "integrity": "sha512-pU3Tsn99pxGdYowXehzZbdDVE+4lDXSGb7p8vA9mSmr569oc2Izh4Zw5vLKSe/Xxn2p5MSNbLVqD4tz+pK6SOw==", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.6", - "rc-util": "^5.7.0" + "rc-motion": "^2.6.1", + "rc-util": "^5.21.2" }, "peerDependencies": { "react": ">=16.9.0", @@ -6300,13 +7136,13 @@ } }, "node_modules/rc-dropdown": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-3.3.3.tgz", - "integrity": "sha512-UNe68VpvtrpU0CS4jh5hD4iGqzi4Pdp7uOya6+H3QIEZxe7K+Xs11BNjZm6W4MaL0jTmzUj+bxvnq5bP3rRoVQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.0.1.tgz", + "integrity": "sha512-OdpXuOcme1rm45cR0Jzgfl1otzmU4vuBVb+etXM8vcaULGokAKVpKlw8p6xzspG7jGd/XxShvq+N3VNEfk/l5g==", "dependencies": { - "@babel/runtime": "^7.10.1", + "@babel/runtime": "^7.18.3", "classnames": "^2.2.6", - "rc-trigger": "^5.0.4", + "rc-trigger": "^5.3.1", "rc-util": "^5.17.0" }, "peerDependencies": { @@ -6315,13 +7151,12 @@ } }, "node_modules/rc-field-form": { - "version": "1.26.2", - "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.26.2.tgz", - "integrity": "sha512-Q1QdpLAt/kxd119kJwGfFvn/ZIzjzTBJsCscy5k0z3g+eRMHkI0Exij6SE2D42N7FAzVkvuXTvzqWSiFGeer7g==", - "peer": true, + "version": "1.27.3", + "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.27.3.tgz", + "integrity": "sha512-HGqxHnmGQgkPApEcikV4qTg3BLPC82uB/cwBDftDt1pYaqitJfSl5TFTTUMKVEJVT5RqJ2Zi68ME1HmIMX2HAw==", "dependencies": { - "@babel/runtime": "^7.8.4", - "async-validator": "^4.0.2", + "@babel/runtime": "^7.18.0", + "async-validator": "^4.1.0", "rc-util": "^5.8.0" }, "engines": { @@ -6333,13 +7168,13 @@ } }, "node_modules/rc-image": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-5.2.5.tgz", - "integrity": "sha512-qUfZjYIODxO0c8a8P5GeuclYXZjzW4hV/5hyo27XqSFo1DmTCs2HkVeQObkcIk5kNsJtgsj1KoPThVsSc/PXOw==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-5.7.1.tgz", + "integrity": "sha512-QyMfdhoUfb5W14plqXSisaYwpdstcLYnB0MjX5ccIK2rydQM9sDPuekQWu500DDGR2dBaIF5vx9XbWkNFK17Fg==", "dependencies": { "@babel/runtime": "^7.11.2", "classnames": "^2.2.6", - "rc-dialog": "~8.6.0", + "rc-dialog": "~8.9.0", "rc-util": "^5.0.6" }, "peerDependencies": { @@ -6348,9 +7183,9 @@ } }, "node_modules/rc-input": { - "version": "0.0.1-alpha.6", - "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-0.0.1-alpha.6.tgz", - "integrity": "sha512-kgpmbxa9vp6kPLW7IP5/Lf6wuaMq+pUq+dPz98vIM58h4wkEKgBQlkMIg9OCEVQIiR8rEPEoe4dO2fc9R0aypQ==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-0.1.3.tgz", + "integrity": "sha512-FgW80AtNA3qTc++BPWXoBPVCGL7oSVbWxcEnBN51pBWpOqiJ6ta79EqtD/WI7k/N1SNqh+ie3GRfPmZhKOj6VQ==", "dependencies": { "@babel/runtime": "^7.11.1", "classnames": "^2.2.1", @@ -6362,13 +7197,13 @@ } }, "node_modules/rc-input-number": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-7.3.4.tgz", - "integrity": "sha512-W9uqSzuvJUnz8H8vsVY4kx+yK51SsAxNTwr8SNH4G3XqQNocLVmKIibKFRjocnYX1RDHMND9FFbgj2h7E7nvGA==", + "version": "7.3.9", + "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-7.3.9.tgz", + "integrity": "sha512-u0+miS+SATdb6DtssYei2JJ1WuZME+nXaG6XGtR8maNyW5uGDytfDu60OTWLQEb0Anv/AcCzehldV8CKmKyQfA==", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.5", - "rc-util": "^5.9.8" + "rc-util": "^5.23.0" }, "peerDependencies": { "react": ">=16.9.0", @@ -6376,16 +7211,16 @@ } }, "node_modules/rc-mentions": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-1.6.5.tgz", - "integrity": "sha512-CUU4+q+awG2pA0l/tG2kPB2ytWbKQUkFxVeKwacr63w7crE/yjfzrFXxs/1fxhyEbQUWdAZt/L25QBieukYQ5w==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-1.10.0.tgz", + "integrity": "sha512-oMlYWnwXSxP2NQVlgxOTzuG/u9BUc3ySY78K3/t7MNhJWpZzXTao+/Bic6tyZLuNCO89//hVQJBdaR2rnFQl6Q==", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.6", - "rc-menu": "~9.3.2", - "rc-textarea": "^0.3.0", + "rc-menu": "~9.6.0", + "rc-textarea": "^0.4.0", "rc-trigger": "^5.0.4", - "rc-util": "^5.0.1" + "rc-util": "^5.22.5" }, "peerDependencies": { "react": ">=16.9.0", @@ -6393,9 +7228,9 @@ } }, "node_modules/rc-menu": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.3.2.tgz", - "integrity": "sha512-h3m45oY1INZyqphGELkdT0uiPnFzxkML8m0VMhJnk2fowtqfiT7F5tJLT3znEVaPIY80vMy1bClCkgq8U91CzQ==", + "version": "9.6.4", + "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.6.4.tgz", + "integrity": "sha512-6DiNAjxjVIPLZXHffXxxcyE15d4isRL7iQ1ru4MqYDH2Cqc5bW96wZOdMydFtGLyDdnmEQ9jVvdCE9yliGvzkw==", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "2.x", @@ -6411,13 +7246,13 @@ } }, "node_modules/rc-motion": { - "version": "2.4.9", - "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.4.9.tgz", - "integrity": "sha512-lrIpBQQ5gIDVedaubnhXuTjC3zpW7HvC/34KyvcHlf6fBjuBlwv45PbonFhmk4Rgu7gLQYrKoMGgFVXqxxyLCw==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.6.2.tgz", + "integrity": "sha512-4w1FaX3dtV749P8GwfS4fYnFG4Rb9pxvCYPc/b2fw1cmlHJWNNgOFIz7ysiD+eOrzJSvnLJWlNQQncpNMXwwpg==", "dependencies": { "@babel/runtime": "^7.11.1", "classnames": "^2.2.1", - "rc-util": "^5.19.2" + "rc-util": "^5.21.0" }, "peerDependencies": { "react": ">=16.9.0", @@ -6425,14 +7260,14 @@ } }, "node_modules/rc-notification": { - "version": "4.5.7", - "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-4.5.7.tgz", - "integrity": "sha512-zhTGUjBIItbx96SiRu3KVURcLOydLUHZCPpYEn1zvh+re//Tnq/wSxN4FKgp38n4HOgHSVxcLEeSxBMTeBBDdw==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-4.6.0.tgz", + "integrity": "sha512-xF3MKgIoynzjQAO4lqsoraiFo3UXNYlBfpHs0VWvwF+4pimen9/H1DYLN2mfRWhHovW6gRpla73m2nmyIqAMZQ==", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "2.x", "rc-motion": "^2.2.0", - "rc-util": "^5.0.1" + "rc-util": "^5.20.1" }, "engines": { "node": ">=8.x" @@ -6443,9 +7278,9 @@ } }, "node_modules/rc-overflow": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.2.4.tgz", - "integrity": "sha512-nIeelyYfdS+mQBK1++FisLZEvZ8xVAzC+duG+TC4TmqNN+kTHraiGntV9/zxDGA1ruyQ91YRJ549JjFodCBnsw==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.2.8.tgz", + "integrity": "sha512-QJ0UItckWPQ37ZL1dMEBAdY1dhfTXFL9k6oTTcyydVwoUNMnMqCGqnRNA98axSr/OeDKqR6DVFyi8eA5RQI/uQ==", "dependencies": { "@babel/runtime": "^7.11.1", "classnames": "^2.2.1", @@ -6458,9 +7293,9 @@ } }, "node_modules/rc-pagination": { - "version": "3.1.15", - "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-3.1.15.tgz", - "integrity": "sha512-4L3fot8g4E+PjWEgoVGX0noFCg+8ZFZmeLH4vsnZpB3O2T2zThtakjNxG+YvSaYtyMVT4B+GLayjKrKbXQpdAg==", + "version": "3.1.17", + "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-3.1.17.tgz", + "integrity": "sha512-/BQ5UxcBnW28vFAcP2hfh+Xg15W0QZn8TWYwdCApchMH1H0CxiaUUcULP8uXcFM1TygcdKWdt3JqsL9cTAfdkQ==", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.1" @@ -6471,9 +7306,9 @@ } }, "node_modules/rc-picker": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-2.6.7.tgz", - "integrity": "sha512-+P2Grt0r2kmCkw2XTp9ew3zTCwBCFEOQLd5BYs+hFaGDSSZwEWJtlbGXAGqWnAUMFx6JrCsKYkDKXDxAWlRz3A==", + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-2.6.11.tgz", + "integrity": "sha512-INJ7ULu+Kj4UgqbcqE8Q+QpMw55xFf9kkyLBHJFk0ihjJpAV4glialRfqHE7k4KX2BWYPQfpILwhwR14x2EiRQ==", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.1", @@ -6493,9 +7328,9 @@ } }, "node_modules/rc-progress": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-3.2.4.tgz", - "integrity": "sha512-M9WWutRaoVkPUPIrTpRIDpX0SPSrVHzxHdCRCbeoBFrd9UFWTYNWRlHsruJM5FH1AZI+BwB4wOJUNNylg/uFSw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-3.3.3.tgz", + "integrity": "sha512-MDVNVHzGanYtRy2KKraEaWeZLri2ZHWIRyaE1a9MQ2MuJ09m+Wxj5cfcaoaR6z5iRpHpA59YeUxAlpML8N4PJw==", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.6", @@ -6538,10 +7373,25 @@ "react-dom": ">=16.9.0" } }, + "node_modules/rc-segmented": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.1.0.tgz", + "integrity": "sha512-hUlonro+pYoZcwrH6Vm56B2ftLfQh046hrwif/VwLIw1j3zGt52p5mREBwmeVzXnSwgnagpOpfafspzs1asjGw==", + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-motion": "^2.4.4", + "rc-util": "^5.17.0" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, "node_modules/rc-select": { - "version": "14.0.6", - "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.0.6.tgz", - "integrity": "sha512-HMb2BwfTvBxMmIWTR/afP4bcRJLbVKFSBW/VFfL5Z+kdV2XlrYdlliK2uHY7pRRvW16PPGwmOwGfV+eoulPINw==", + "version": "14.1.13", + "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.1.13.tgz", + "integrity": "sha512-WMEsC3gTwA1dbzWOdVIXDmWyidYNLq68AwvvUlRROw790uGUly0/vmqDozXrIr0QvN/A3CEULx12o+WtLCAefg==", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "2.x", @@ -6610,14 +7460,14 @@ } }, "node_modules/rc-table": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.23.2.tgz", - "integrity": "sha512-opc2IBJOetsPSdNI+u1Lh9yY4Ks+EMgo1oJzZN+yIV4fRcgP81tHtxdPOVvXPFI4rUMO8CKnmHbGPU7jxMRAeg==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.26.0.tgz", + "integrity": "sha512-0cD8e6S+DTGAt5nBZQIPFYEaIukn17sfa5uFL98faHlH/whZzD8ii3dbFL4wmUDEL4BLybhYop+QUfZJ4CPvNQ==", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.5", "rc-resize-observer": "^1.1.0", - "rc-util": "^5.14.0", + "rc-util": "^5.22.5", "shallowequal": "^1.1.0" }, "engines": { @@ -6629,14 +7479,15 @@ } }, "node_modules/rc-tabs": { - "version": "11.10.8", - "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-11.10.8.tgz", - "integrity": "sha512-uK+x+eJ8WM4jiXoqGa+P+JUQX2Wlkj9f0o/5dyOw42B6YLnHJN80uTVcCeAmtA1N0xjPW0GNSZvUm4SU3jAYpw==", + "version": "12.2.1", + "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-12.2.1.tgz", + "integrity": "sha512-09pVv4kN8VFqp6THceEmxOW8PAShQC08hrroeVYP4Y8YBFaP1PIWdyFL01czcbyz5YZFj9flZ7aljMaAl0jLVg==", "dependencies": { "@babel/runtime": "^7.11.2", "classnames": "2.x", - "rc-dropdown": "^3.2.0", - "rc-menu": "~9.3.2", + "rc-dropdown": "~4.0.0", + "rc-menu": "~9.6.0", + "rc-motion": "^2.6.2", "rc-resize-observer": "^1.0.0", "rc-util": "^5.5.0" }, @@ -6649,9 +7500,9 @@ } }, "node_modules/rc-textarea": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-0.3.7.tgz", - "integrity": "sha512-yCdZ6binKmAQB13hc/oehh0E/QRwoPP1pjF21aHBxlgXO3RzPF6dUu4LG2R4FZ1zx/fQd2L1faktulrXOM/2rw==", + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-0.4.5.tgz", + "integrity": "sha512-WHeJRgUlloNyVgTsItMrIXwMhU6P3NmrUDkxX+JRwEpJjECsKtZNlNcXe9pHNLCaYQ3Z1cVCfsClhgDDgJ2kFQ==", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.1", @@ -6665,11 +7516,12 @@ } }, "node_modules/rc-tooltip": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-5.1.1.tgz", - "integrity": "sha512-alt8eGMJulio6+4/uDm7nvV+rJq9bsfxFDCI0ljPdbuoygUscbsMYb6EQgwib/uqsXQUvzk+S7A59uYHmEgmDA==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-5.2.2.tgz", + "integrity": "sha512-jtQzU/18S6EI3lhSGoDYhPqNpWajMtS5VV/ld1LwyfrDByQpYmw/LW6U7oFXXLukjfDHQ7Ju705A82PRNFWYhg==", "dependencies": { "@babel/runtime": "^7.11.2", + "classnames": "^2.3.1", "rc-trigger": "^5.0.0" }, "peerDependencies": { @@ -6678,15 +7530,15 @@ } }, "node_modules/rc-tree": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.4.4.tgz", - "integrity": "sha512-2qoObRgp31DBXmVzMJmo4qmwP20XEa4hR3imWQtRPcgN3pmljW3WKFmZRrYdOFHz7CyTnRsFZR065bBkIoUpiA==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.7.0.tgz", + "integrity": "sha512-F+Ewkv/UcutshnVBMISP+lPdHDlcsL+YH/MQDVWbk+QdkfID7vXiwrHMEZn31+2Rbbm21z/HPceGS8PXGMmnQg==", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "2.x", "rc-motion": "^2.0.1", "rc-util": "^5.16.1", - "rc-virtual-list": "^3.4.2" + "rc-virtual-list": "^3.4.8" }, "engines": { "node": ">=10.x" @@ -6697,14 +7549,14 @@ } }, "node_modules/rc-tree-select": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.1.5.tgz", - "integrity": "sha512-OXAwCFO0pQmb48NcjUJtiX6rp4FroCXMfzqPmuVVoBGBV/uwO1TPyb+uBZ2/972zkCA8u4je5M5Qx51sL8y7jg==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.5.3.tgz", + "integrity": "sha512-gv8KyC6J7f9e50OkGk1ibF7v8vL+iaBnA8Ep/EVlMma2/tGdBQXO9xIvPjX8eQrZL5PjoeTUndNPM3cY3721ng==", "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "2.x", - "rc-select": "~14.0.0-alpha.8", - "rc-tree": "~5.4.3", + "rc-select": "~14.1.0", + "rc-tree": "~5.7.0", "rc-util": "^5.16.1" }, "peerDependencies": { @@ -6713,11 +7565,11 @@ } }, "node_modules/rc-trigger": { - "version": "5.2.15", - "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-5.2.15.tgz", - "integrity": "sha512-VxZWqCObtUOzs9V9Be0dDA2JGchriDpvQaJpsCI2EQ4+KWHIvjFz6Ziina4uxK5drRsn0RnBi7nngmTl9j/F7Q==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-5.3.1.tgz", + "integrity": "sha512-5gaFbDkYSefZ14j2AdzucXzlWgU2ri5uEjkHvsf1ynRhdJbKxNOnw4PBZ9+FVULNGFiDzzlVF8RJnR9P/xrnKQ==", "dependencies": { - "@babel/runtime": "^7.11.2", + "@babel/runtime": "^7.18.3", "classnames": "^2.2.6", "rc-align": "^4.0.0", "rc-motion": "^2.0.0", @@ -6746,11 +7598,11 @@ } }, "node_modules/rc-util": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.20.1.tgz", - "integrity": "sha512-2IEyErPAYl0Up5gBu71e8IkOs+/SL9XRUvnGhtsr7IHlXLx2OsbQKTDpWacJbzLCmNcgJylDGj1kiklx+zagRA==", + "version": "5.24.4", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.24.4.tgz", + "integrity": "sha512-2a4RQnycV9eV7lVZPEJ7QwJRPlZNc06J7CwcwZo4vIHr3PfUqtYgl1EkUV9ETAc6VRRi8XZOMFhYG63whlIC9Q==", "dependencies": { - "@babel/runtime": "^7.12.5", + "@babel/runtime": "^7.18.3", "react-is": "^16.12.0", "shallowequal": "^1.1.0" }, @@ -6760,9 +7612,9 @@ } }, "node_modules/rc-virtual-list": { - "version": "3.4.6", - "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.4.6.tgz", - "integrity": "sha512-wMJ7Bl+AxgIDojp0VxuQxjpNulKodwxGXSsTyxA9Mwzwemj5vKAgTbkPT64ZW5ORf8FOQAaPRlMiTADrPEo3sQ==", + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.4.10.tgz", + "integrity": "sha512-Jv0cgJxJ+8F/YViW8WGs/jQF2rmT8RUcJ5uDJs5MOFLTYLAvCpM/xU+Zu6EpCun50fmovhXiItQctcfE2UY3Aw==", "dependencies": { "classnames": "^2.2.6", "rc-resize-observer": "^1.0.0", @@ -6835,6 +7687,41 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-markdown": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.3.tgz", + "integrity": "sha512-We36SfqaKoVNpN1QqsZwWSv/OZt5J15LNgTLWynwAN5b265hrQrsjMtlRNwUvS+YyR3yDM8HpTNc4pK9H/Gc0A==", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/prop-types": "^15.0.0", + "@types/unist": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^2.0.0", + "prop-types": "^15.0.0", + "property-information": "^6.0.0", + "react-is": "^18.0.0", + "remark-parse": "^10.0.0", + "remark-rehype": "^10.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.3.0", + "unified": "^10.0.0", + "unist-util-visit": "^4.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/react-markdown/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, "node_modules/react-router": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz", @@ -7005,6 +7892,35 @@ "node": ">= 0.10" } }, + "node_modules/remark-parse": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", + "integrity": "sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-10.1.0.tgz", + "integrity": "sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-to-hast": "^12.1.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/renderkid": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", @@ -7130,6 +8046,17 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -7463,6 +8390,15 @@ "node": ">=0.10.0" } }, + "node_modules/space-separated-tokens": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.1.tgz", + "integrity": "sha512-ekwEbFp5aqSPKaqeY1PGrlGQxPNaq+Cnx4+bE2D8sciBQrHpbwoBbawqTN2+6jPs9IdWxxiUcN0K2pkczD3zmw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/spdy": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", @@ -7534,7 +8470,7 @@ "node_modules/string-convert": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", - "integrity": "sha1-aYLMMEn7tM2F+LJFaLnZvznu/5c=" + "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==" }, "node_modules/strip-ansi": { "version": "6.0.1", @@ -7573,6 +8509,14 @@ "webpack": "^5.0.0" } }, + "node_modules/style-to-object": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", + "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", + "dependencies": { + "inline-style-parser": "0.1.1" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -7615,14 +8559,14 @@ } }, "node_modules/terser": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.12.1.tgz", - "integrity": "sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ==", + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", + "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", "dev": true, "dependencies": { + "@jridgewell/source-map": "^0.3.2", "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "bin": { @@ -7699,15 +8643,6 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, - "node_modules/terser/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, "node_modules/thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", @@ -7757,6 +8692,24 @@ "node": ">=0.6" } }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", @@ -7816,6 +8769,116 @@ "node": ">=4" } }, + "node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unified/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unist-builder": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-3.0.0.tgz", + "integrity": "sha512-GFxmfEAa0vi9i5sd0R2kcrI9ks0r82NasRq5QHh2ysGngrc6GiqD5CDf1FjPenY4vApmFASBIIlk/jj5J5YbmQ==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-generated": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.0.tgz", + "integrity": "sha512-TiWE6DVtVe7Ye2QxOVW9kqybs6cZexNwTwSMVgkfjEReqy/xwGpAXb99OxktoWwmL+Z+Epb0Dn8/GNDYP1wnUw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.1.1.tgz", + "integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-4.0.3.tgz", + "integrity": "sha512-p/5EMGIa1qwbXjA+QgcBXaPWjSnZfQ2Sc3yBEEfgPwsEmJd8Qh+DSk3LGnmOM4S1bY2C0AjmMnB8RuEYxpPwXQ==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.1.tgz", + "integrity": "sha512-n9KN3WV9k4h1DxYR1LoajgN93wpEi/7ZplVe02IoB4gH5ctI1AaF2670BLHQYbwj+pY83gFtyeySFiyMHJklrg==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.1.tgz", + "integrity": "sha512-gks4baapT/kNRaWxuGkl5BIhoanZo7sC/cUT/JToSRNL1dYoXRFl75d++NkjYk4TAu2uv2Px+l8guMajogeuiw==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -7885,6 +8948,23 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/uvu": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", + "dependencies": { + "dequal": "^2.0.0", + "diff": "^5.0.0", + "kleur": "^4.0.3", + "sade": "^1.7.3" + }, + "bin": { + "uvu": "bin.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -7894,6 +8974,34 @@ "node": ">= 0.8" } }, + "node_modules/vfile": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.5.tgz", + "integrity": "sha512-U1ho2ga33eZ8y8pkbQLH54uKqGhFJ6GYIHnnG5AhRpAh3OWjkrRHKa/KogbmQn8We+c0KVV3rTOgR9V/WowbXQ==", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.2.tgz", + "integrity": "sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/virtuallist-antd": { "version": "0.7.4-beta.0", "resolved": "https://registry.npmjs.org/virtuallist-antd/-/virtuallist-antd-0.7.4-beta.0.tgz", @@ -8351,24 +9459,24 @@ } }, "node_modules/xterm": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/xterm/-/xterm-4.18.0.tgz", - "integrity": "sha512-JQoc1S0dti6SQfI0bK1AZvGnAxH4MVw45ZPFSO6FHTInAiau3Ix77fSxNx3mX4eh9OL4AYa8+4C8f5UvnSfppQ==" + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.0.0.tgz", + "integrity": "sha512-tmVsKzZovAYNDIaUinfz+VDclraQpPUnAME+JawosgWRMphInDded/PuY0xmU5dOhyeYZsI0nz5yd8dPYsdLTA==" }, "node_modules/xterm-addon-fit": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.5.0.tgz", - "integrity": "sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.6.0.tgz", + "integrity": "sha512-9/7A+1KEjkFam0yxTaHfuk9LEvvTSBi0PZmEkzJqgafXPEXL9pCMAVV7rB09sX6ATRDXAdBpQhZkhKj7CGvYeg==", "peerDependencies": { - "xterm": "^4.0.0" + "xterm": "^5.0.0" } }, "node_modules/xterm-addon-web-links": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/xterm-addon-web-links/-/xterm-addon-web-links-0.5.1.tgz", - "integrity": "sha512-dBjbOIrCNmxAcUQkkSrKj9BM6yLpmqUpZ9SOCUuZe/sznPl4d8OBZQClK7VcdZ0vf0+5i5Fce2rUUrew/XTZTg==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/xterm-addon-web-links/-/xterm-addon-web-links-0.7.0.tgz", + "integrity": "sha512-6PqoqzzPwaeSq22skzbvyboDvSnYk5teUYEoKBwMYvhbkwOQkemZccjWHT5FnNA8o1aInTc4PRYAl4jjPucCKA==", "peerDependencies": { - "xterm": "^4.0.0" + "xterm": "^5.0.0" } }, "node_modules/yallist": { @@ -8414,54 +9522,145 @@ "integrity": "sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw==" }, "@ant-design/pro-card": { - "version": "1.19.4", - "resolved": "https://registry.npmjs.org/@ant-design/pro-card/-/pro-card-1.19.4.tgz", - "integrity": "sha512-pN2xHJ3xpxI0vqc3iOywBKNvqO6x+7IYx01V165ZZboek69Tl8eygr/yGiArIySik/mjZAyP8Ensk8fqxz6WnA==", + "version": "1.20.22", + "resolved": "https://registry.npmjs.org/@ant-design/pro-card/-/pro-card-1.20.22.tgz", + "integrity": "sha512-du4yMSLflfI+SOx7n87FtiPaEmGtWDN4yFC2vfQZQ6rhO0SVAOI2vRPKoXKOZn8Pr9fXVQGo+uPsVXJMZ3WwPg==", "requires": { "@ant-design/icons": "^4.2.1", - "@ant-design/pro-utils": "1.39.1", - "@babel/runtime": "^7.16.3", + "@ant-design/pro-utils": "1.45.3", + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", "classnames": "^2.2.6", "omit.js": "^2.0.2", "rc-util": "^5.4.0" + }, + "dependencies": { + "@ant-design/pro-provider": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@ant-design/pro-provider/-/pro-provider-1.10.0.tgz", + "integrity": "sha512-gbQtq+Qlnob6aEghiWX/kXEzNhe4eOFlv5Ue2/xsal+22qvot/kFoOB652TD76fMI7vlkoema1pTKsvD5Uji6A==", + "requires": { + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", + "rc-util": "^5.0.1", + "swr": "^1.2.0" + } + }, + "@ant-design/pro-utils": { + "version": "1.45.3", + "resolved": "https://registry.npmjs.org/@ant-design/pro-utils/-/pro-utils-1.45.3.tgz", + "integrity": "sha512-W2qtyckdkHTWGVXfFfqb9s/ahq3o4GlIZC3+WDiGUgqJTsUkwY69yV67E2ZfAro1XRXblUzbvxIv96M7bEAfFg==", + "requires": { + "@ant-design/icons": "^4.3.0", + "@ant-design/pro-provider": "1.10.0", + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", + "classnames": "^2.2.6", + "moment": "^2.27.0", + "rc-util": "^5.0.6", + "react-sortable-hoc": "^2.0.0", + "swr": "^1.2.0" + } + } } }, "@ant-design/pro-field": { - "version": "1.34.4", - "resolved": "https://registry.npmjs.org/@ant-design/pro-field/-/pro-field-1.34.4.tgz", - "integrity": "sha512-PPKihq+Gw4aV456ChVXBY3u6UwO835SxACo/u2zIB+J1k0mgn3kB6HjYAbgasrVtm6cFC4Q5I+otLO6H8G/8Wg==", + "version": "1.36.7", + "resolved": "https://registry.npmjs.org/@ant-design/pro-field/-/pro-field-1.36.7.tgz", + "integrity": "sha512-N5DGitBT2o5UC5lR8M6CQOhKsTMqhzggR6Q0xC2Uj50eUmy5A2uFDnsCjlaSgprocpIK0/zvTU02V9yE62SHSw==", "requires": { "@ant-design/icons": "^4.2.1", - "@ant-design/pro-provider": "1.6.3", - "@ant-design/pro-utils": "1.39.1", - "@babel/runtime": "^7.16.3", + "@ant-design/pro-provider": "1.10.0", + "@ant-design/pro-utils": "1.45.3", + "@babel/runtime": "^7.18.0", "@chenshuai2144/sketch-color": "^1.0.8", + "antd": "^4.20.0 ", "classnames": "^2.2.6", + "lodash.omit": "^4.5.0", "lodash.tonumber": "^4.0.3", "moment": "^2.27.0", "omit.js": "^2.0.2", "rc-util": "^5.4.0", "swr": "^1.2.0" + }, + "dependencies": { + "@ant-design/pro-provider": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@ant-design/pro-provider/-/pro-provider-1.10.0.tgz", + "integrity": "sha512-gbQtq+Qlnob6aEghiWX/kXEzNhe4eOFlv5Ue2/xsal+22qvot/kFoOB652TD76fMI7vlkoema1pTKsvD5Uji6A==", + "requires": { + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", + "rc-util": "^5.0.1", + "swr": "^1.2.0" + } + }, + "@ant-design/pro-utils": { + "version": "1.45.3", + "resolved": "https://registry.npmjs.org/@ant-design/pro-utils/-/pro-utils-1.45.3.tgz", + "integrity": "sha512-W2qtyckdkHTWGVXfFfqb9s/ahq3o4GlIZC3+WDiGUgqJTsUkwY69yV67E2ZfAro1XRXblUzbvxIv96M7bEAfFg==", + "requires": { + "@ant-design/icons": "^4.3.0", + "@ant-design/pro-provider": "1.10.0", + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", + "classnames": "^2.2.6", + "moment": "^2.27.0", + "rc-util": "^5.0.6", + "react-sortable-hoc": "^2.0.0", + "swr": "^1.2.0" + } + } } }, "@ant-design/pro-form": { - "version": "1.64.0", - "resolved": "https://registry.npmjs.org/@ant-design/pro-form/-/pro-form-1.64.0.tgz", - "integrity": "sha512-PDGRATaN/GbiSD+dA3dMuhRtB/2rXa2Ztm59UOneugYYzygRkVeEuHlxv/q1zahvJOfVzLykVZBnzsK8J7wTyw==", + "version": "1.74.7", + "resolved": "https://registry.npmjs.org/@ant-design/pro-form/-/pro-form-1.74.7.tgz", + "integrity": "sha512-3r6DdAkvsjN0lpVnbpAbtj5n+Od+IeLE6Z6DKPChobtwYJX5XyR8fWWOnyR43W8qbGTpXMxDwO9IP3VRY7VdMQ==", "requires": { "@ant-design/icons": "^4.2.1", - "@ant-design/pro-field": "1.34.4", - "@ant-design/pro-provider": "1.6.3", - "@ant-design/pro-utils": "1.39.1", - "@babel/runtime": "^7.16.3", + "@ant-design/pro-field": "1.36.7", + "@ant-design/pro-provider": "1.10.0", + "@ant-design/pro-utils": "1.45.3", + "@babel/runtime": "^7.18.0", "@umijs/use-params": "^1.0.9", + "antd": "^4.20.0 ", "classnames": "^2.2.6", - "lodash": "^4.17.21", + "lodash.merge": "^4.6.2", "omit.js": "^2.0.2", "rc-resize-observer": "^1.1.0", "rc-util": "^5.0.6", "use-json-comparison": "^1.0.5", - "use-media-antd-query": "^1.0.6" + "use-media-antd-query": "^1.1.0" + }, + "dependencies": { + "@ant-design/pro-provider": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@ant-design/pro-provider/-/pro-provider-1.10.0.tgz", + "integrity": "sha512-gbQtq+Qlnob6aEghiWX/kXEzNhe4eOFlv5Ue2/xsal+22qvot/kFoOB652TD76fMI7vlkoema1pTKsvD5Uji6A==", + "requires": { + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", + "rc-util": "^5.0.1", + "swr": "^1.2.0" + } + }, + "@ant-design/pro-utils": { + "version": "1.45.3", + "resolved": "https://registry.npmjs.org/@ant-design/pro-utils/-/pro-utils-1.45.3.tgz", + "integrity": "sha512-W2qtyckdkHTWGVXfFfqb9s/ahq3o4GlIZC3+WDiGUgqJTsUkwY69yV67E2ZfAro1XRXblUzbvxIv96M7bEAfFg==", + "requires": { + "@ant-design/icons": "^4.3.0", + "@ant-design/pro-provider": "1.10.0", + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", + "classnames": "^2.2.6", + "moment": "^2.27.0", + "rc-util": "^5.0.6", + "react-sortable-hoc": "^2.0.0", + "swr": "^1.2.0" + } + } } }, "@ant-design/pro-layout": { @@ -8500,17 +9699,18 @@ } }, "@ant-design/pro-table": { - "version": "2.71.6", - "resolved": "https://registry.npmjs.org/@ant-design/pro-table/-/pro-table-2.71.6.tgz", - "integrity": "sha512-GfeNY/hgMzWSYOrfQ4fgmw4T46FeSroUvDmV8GOzNd8P0HlfukDlztDXfzjVdrez4g9Y0Ub8uF0EIMjFETgL7g==", + "version": "2.80.8", + "resolved": "https://registry.npmjs.org/@ant-design/pro-table/-/pro-table-2.80.8.tgz", + "integrity": "sha512-QPrGJJpXk8va/sUMlBYXIxNenc0OMHK+LKKLKOmh1hoA+a6/a75Tk+VaoncLGZZ99qXDQwMLlRZXMGDhrtCGgA==", "requires": { "@ant-design/icons": "^4.1.0", - "@ant-design/pro-card": "1.19.4", - "@ant-design/pro-field": "1.34.4", - "@ant-design/pro-form": "1.64.0", - "@ant-design/pro-provider": "1.6.3", - "@ant-design/pro-utils": "1.39.1", - "@babel/runtime": "^7.16.3", + "@ant-design/pro-card": "1.20.22", + "@ant-design/pro-field": "1.36.7", + "@ant-design/pro-form": "1.74.7", + "@ant-design/pro-provider": "1.10.0", + "@ant-design/pro-utils": "1.45.3", + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", "classnames": "^2.2.6", "moment": "^2.24.0", "omit.js": "^2.0.2", @@ -8519,6 +9719,35 @@ "unstated-next": "^1.1.0", "use-json-comparison": "^1.0.5", "use-media-antd-query": "^1.1.0" + }, + "dependencies": { + "@ant-design/pro-provider": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@ant-design/pro-provider/-/pro-provider-1.10.0.tgz", + "integrity": "sha512-gbQtq+Qlnob6aEghiWX/kXEzNhe4eOFlv5Ue2/xsal+22qvot/kFoOB652TD76fMI7vlkoema1pTKsvD5Uji6A==", + "requires": { + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", + "rc-util": "^5.0.1", + "swr": "^1.2.0" + } + }, + "@ant-design/pro-utils": { + "version": "1.45.3", + "resolved": "https://registry.npmjs.org/@ant-design/pro-utils/-/pro-utils-1.45.3.tgz", + "integrity": "sha512-W2qtyckdkHTWGVXfFfqb9s/ahq3o4GlIZC3+WDiGUgqJTsUkwY69yV67E2ZfAro1XRXblUzbvxIv96M7bEAfFg==", + "requires": { + "@ant-design/icons": "^4.3.0", + "@ant-design/pro-provider": "1.10.0", + "@babel/runtime": "^7.18.0", + "antd": "^4.20.0 ", + "classnames": "^2.2.6", + "moment": "^2.27.0", + "rc-util": "^5.0.6", + "react-sortable-hoc": "^2.0.0", + "swr": "^1.2.0" + } + } } }, "@ant-design/pro-utils": { @@ -8537,15 +9766,15 @@ } }, "@ant-design/react-slick": { - "version": "0.28.4", - "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-0.28.4.tgz", - "integrity": "sha512-j9eAHTn7GxbXUFNknJoHS2ceAsqrQi2j8XykjZE1IXCD8kJF+t28EvhBLniDpbOsBk/3kjalnhriTfZcjBHNqg==", + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-0.29.2.tgz", + "integrity": "sha512-kgjtKmkGHa19FW21lHnAfyyH9AAoh35pBdcJ53rHmQ3O+cfFHGHnUbj/HFrRNJ5vIts09FKJVAD8RpaC+RaWfA==", "requires": { "@babel/runtime": "^7.10.4", "classnames": "^2.2.5", "json2mq": "^0.2.0", "lodash": "^4.17.21", - "resize-observer-polyfill": "^1.5.0" + "resize-observer-polyfill": "^1.5.1" } }, "@babel/code-frame": { @@ -9636,9 +10865,9 @@ } }, "@babel/runtime": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", - "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.4.tgz", + "integrity": "sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==", "requires": { "regenerator-runtime": "^0.13.4" } @@ -9702,26 +10931,53 @@ "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", "dev": true }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", "dev": true }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "@leichtgewicht/ip-codec": { @@ -9799,6 +11055,14 @@ "@types/node": "*" } }, + "@types/debug": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", + "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "requires": { + "@types/ms": "*" + } + }, "@types/eslint": { "version": "8.4.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", @@ -9858,6 +11122,14 @@ "@types/node": "*" } }, + "@types/hast": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", + "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", + "requires": { + "@types/unist": "*" + } + }, "@types/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -9879,6 +11151,14 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, + "@types/mdast": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", + "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==", + "requires": { + "@types/unist": "*" + } + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -9891,12 +11171,22 @@ "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", "dev": true }, + "@types/ms": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", + "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + }, "@types/node": { "version": "17.0.24", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.24.tgz", "integrity": "sha512-aveCYRQbgTH9Pssp1voEP7HiuWlD2jW2BO56w+bVrJn04i61yh6mRfoKO6hEYQD9vF+W8Chkwc6j1M36uPkx4g==", "dev": true }, + "@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, "@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", @@ -9909,12 +11199,29 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, + "@types/react": { + "version": "18.0.24", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.24.tgz", + "integrity": "sha512-wRJWT6ouziGUy+9uX0aW4YOJxAY0bG6/AOk5AW5QSvZqI7dk6VBIbXvcVgIw/W5Jrl24f77df98GEKTJGOLx7Q==", + "peer": true, + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, "@types/retry": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", "dev": true }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", + "peer": true + }, "@types/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", @@ -9943,6 +11250,11 @@ "@types/node": "*" } }, + "@types/unist": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", + "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" + }, "@types/ws": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", @@ -10253,52 +11565,53 @@ } }, "antd": { - "version": "4.19.5", - "resolved": "https://registry.npmjs.org/antd/-/antd-4.19.5.tgz", - "integrity": "sha512-C4H/VJqlVO5iMvHZyiV27R8SbPs4jsOKCGPhDXIHUry/RnUCbMmVeQaPRfUIxSI1NbqDflsuQfevPtz1svyIlg==", + "version": "4.23.6", + "resolved": "https://registry.npmjs.org/antd/-/antd-4.23.6.tgz", + "integrity": "sha512-AYH57cWBDe1ChtbnvG8i9dpKG4WnjE3AG0zIKpXByFNnxsr4saV6/19ihE8/ImSGpohN4E2zTXmo7R5/MyVRKQ==", "requires": { "@ant-design/colors": "^6.0.0", "@ant-design/icons": "^4.7.0", - "@ant-design/react-slick": "~0.28.1", - "@babel/runtime": "^7.12.5", + "@ant-design/react-slick": "~0.29.1", + "@babel/runtime": "^7.18.3", "@ctrl/tinycolor": "^3.4.0", "classnames": "^2.2.6", "copy-to-clipboard": "^3.2.0", "lodash": "^4.17.21", "memoize-one": "^6.0.0", - "moment": "^2.25.3", - "rc-cascader": "~3.2.1", + "moment": "^2.29.2", + "rc-cascader": "~3.7.0", "rc-checkbox": "~2.3.0", - "rc-collapse": "~3.1.0", - "rc-dialog": "~8.6.0", - "rc-drawer": "~4.4.2", - "rc-dropdown": "~3.3.2", - "rc-field-form": "~1.25.0", - "rc-image": "~5.2.5", - "rc-input": "~0.0.1-alpha.5", - "rc-input-number": "~7.3.0", - "rc-mentions": "~1.6.1", - "rc-menu": "~9.3.2", - "rc-motion": "^2.4.4", - "rc-notification": "~4.5.7", - "rc-pagination": "~3.1.9", - "rc-picker": "~2.6.4", - "rc-progress": "~3.2.1", + "rc-collapse": "~3.3.0", + "rc-dialog": "~8.9.0", + "rc-drawer": "~5.1.0", + "rc-dropdown": "~4.0.0", + "rc-field-form": "~1.27.0", + "rc-image": "~5.7.0", + "rc-input": "~0.1.2", + "rc-input-number": "~7.3.9", + "rc-mentions": "~1.10.0", + "rc-menu": "~9.6.3", + "rc-motion": "^2.6.1", + "rc-notification": "~4.6.0", + "rc-pagination": "~3.1.17", + "rc-picker": "~2.6.11", + "rc-progress": "~3.3.2", "rc-rate": "~2.9.0", "rc-resize-observer": "^1.2.0", - "rc-select": "~14.0.2", - "rc-slider": "~10.0.0-alpha.4", + "rc-segmented": "~2.1.0", + "rc-select": "~14.1.13", + "rc-slider": "~10.0.0", "rc-steps": "~4.1.0", "rc-switch": "~3.2.0", - "rc-table": "~7.23.0", - "rc-tabs": "~11.10.0", - "rc-textarea": "~0.3.0", - "rc-tooltip": "~5.1.1", - "rc-tree": "~5.4.3", - "rc-tree-select": "~5.1.1", + "rc-table": "~7.26.0", + "rc-tabs": "~12.2.0", + "rc-textarea": "~0.4.5", + "rc-tooltip": "~5.2.0", + "rc-tree": "~5.7.0", + "rc-tree-select": "~5.5.0", "rc-trigger": "^5.2.10", "rc-upload": "~4.3.0", - "rc-util": "^5.19.3", + "rc-util": "^5.22.5", "scroll-into-view-if-needed": "^2.2.25" }, "dependencies": { @@ -10306,16 +11619,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" - }, - "rc-field-form": { - "version": "1.25.2", - "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.25.2.tgz", - "integrity": "sha512-FXGScWibDlwIlKY15T1YOA7VTtMJwqxxXdDjHB56ZNx7wGbE4vK+Fe2zcymyakGZD0ej8NUP5LGr7qBVWaVpUQ==", - "requires": { - "@babel/runtime": "^7.8.4", - "async-validator": "^4.0.2", - "rc-util": "^5.8.0" - } } } }, @@ -10369,9 +11672,9 @@ } }, "async-validator": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.0.7.tgz", - "integrity": "sha512-Pj2IR7u8hmUEDOwB++su6baaRi+QvsgajuFB9j95foM1N2gy5HM4z60hfusIO0fBPG5uLAEl6yCJr1jNSVugEQ==" + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==" }, "axios": { "version": "0.26.1", @@ -10432,6 +11735,11 @@ "@babel/helper-define-polyfill-provider": "^0.3.1" } }, + "bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -10601,6 +11909,11 @@ "supports-color": "^5.3.0" } }, + "character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==" + }, "chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -10707,6 +12020,11 @@ "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", "dev": true }, + "comma-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.2.tgz", + "integrity": "sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg==" + }, "commander": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", @@ -10968,6 +12286,11 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, + "crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==" + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -10979,11 +12302,6 @@ "which": "^2.0.1" } }, - "crypto-js": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", - "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" - }, "css-loader": { "version": "6.7.1", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", @@ -11036,25 +12354,38 @@ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true }, + "csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", + "peer": true + }, "date-fns": { - "version": "2.28.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", - "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==" + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==" }, "dayjs": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.1.tgz", - "integrity": "sha512-ER7EjqVAMkRRsxNCC5YqJ9d9VQYuWdGt7aiH2qA5R5wt8ZmWaP2dLUSIK6y/kVzLMlmh1Tvu5xUf4M/wdGJ5KA==" + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz", + "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==" }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "requires": { "ms": "2.1.2" } }, + "decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "requires": { + "character-entities": "^2.0.0" + } + }, "default-gateway": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", @@ -11141,6 +12472,11 @@ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", "dev": true }, + "dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" + }, "destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", @@ -11153,6 +12489,11 @@ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true }, + "diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==" + }, "diff-match-patch": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", @@ -11476,6 +12817,11 @@ } } }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -11749,6 +13095,11 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, + "hast-util-whitespace": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.0.tgz", + "integrity": "sha512-Pkw+xBHuV6xFeJprJe2BBEoDV+AvQySaz3pPDRUs5PNZEMQjpXJJueqrpcHIXxnWTcAGi/UOCgVShlkY6kLoqg==" + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -11965,6 +13316,11 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" + }, "interpret": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", @@ -11994,6 +13350,11 @@ "binary-extensions": "^2.0.0" } }, + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + }, "is-core-module": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", @@ -12162,7 +13523,7 @@ "json2mq": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", - "integrity": "sha1-tje9O6nqvhIsg+lyBIOusQ0skEo=", + "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==", "requires": { "string-convert": "^0.2.0" } @@ -12179,6 +13540,11 @@ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, + "kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==" + }, "klona": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", @@ -12291,6 +13657,11 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, + "lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==" + }, "lodash.tonumber": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/lodash.tonumber/-/lodash.tonumber-4.0.3.tgz", @@ -12331,6 +13702,56 @@ "semver": "^6.0.0" } }, + "mdast-util-definitions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.1.tgz", + "integrity": "sha512-rQ+Gv7mHttxHOBx2dkF4HWTg+EE+UR78ptQWDylzPKaQuVGdG4HIoY3SrS/pCp80nZ04greFvXbVFHT+uf0JVQ==", + "requires": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "unist-util-visit": "^4.0.0" + } + }, + "mdast-util-from-markdown": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz", + "integrity": "sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==", + "requires": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + } + }, + "mdast-util-to-hast": { + "version": "12.2.4", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.2.4.tgz", + "integrity": "sha512-a21xoxSef1l8VhHxS1Dnyioz6grrJkoaCUgGzMD/7dWHvboYX3VW53esRUfB5tgTyz4Yos1n25SPcj35dJqmAg==", + "requires": { + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-definitions": "^5.0.0", + "micromark-util-sanitize-uri": "^1.1.0", + "trim-lines": "^3.0.0", + "unist-builder": "^3.0.0", + "unist-util-generated": "^2.0.0", + "unist-util-position": "^4.0.0", + "unist-util-visit": "^4.0.0" + } + }, + "mdast-util-to-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz", + "integrity": "sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==" + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -12375,6 +13796,218 @@ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", "dev": true }, + "micromark": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.1.0.tgz", + "integrity": "sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==", + "requires": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "micromark-core-commonmark": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz", + "integrity": "sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==", + "requires": { + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "micromark-factory-destination": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz", + "integrity": "sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-factory-label": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz", + "integrity": "sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-factory-space": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz", + "integrity": "sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-factory-title": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz", + "integrity": "sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A==", + "requires": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-factory-whitespace": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz", + "integrity": "sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A==", + "requires": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.1.0.tgz", + "integrity": "sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg==", + "requires": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-chunked": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz", + "integrity": "sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==", + "requires": { + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-classify-character": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz", + "integrity": "sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-combine-extensions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz", + "integrity": "sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==", + "requires": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-decode-numeric-character-reference": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz", + "integrity": "sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==", + "requires": { + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-decode-string": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz", + "integrity": "sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q==", + "requires": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-encode": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz", + "integrity": "sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA==" + }, + "micromark-util-html-tag-name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.1.0.tgz", + "integrity": "sha512-BKlClMmYROy9UiV03SwNmckkjn8QHVaWkqoAqzivabvdGcwNGMMMH/5szAnywmsTBUzDsU57/mFi0sp4BQO6dA==" + }, + "micromark-util-normalize-identifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz", + "integrity": "sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==", + "requires": { + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-resolve-all": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz", + "integrity": "sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==", + "requires": { + "micromark-util-types": "^1.0.0" + } + }, + "micromark-util-sanitize-uri": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.1.0.tgz", + "integrity": "sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg==", + "requires": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "micromark-util-subtokenize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz", + "integrity": "sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA==", + "requires": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "micromark-util-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz", + "integrity": "sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ==" + }, + "micromark-util-types": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.0.2.tgz", + "integrity": "sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w==" + }, "micromatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", @@ -12443,15 +14076,19 @@ } }, "moment": { - "version": "2.29.2", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.2.tgz", - "integrity": "sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg==" + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" + }, + "mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==" }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "multicast-dns": { "version": "7.2.4", @@ -12900,6 +14537,11 @@ "react-is": "^16.13.1" } }, + "property-information": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.1.1.tgz", + "integrity": "sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w==" + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -12994,15 +14636,15 @@ } }, "rc-cascader": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.2.9.tgz", - "integrity": "sha512-Mvkegzf506PD7qc38kg2tGllIBXs5dio3DPg+NER7SiOfCXBCATWYEs0CbUp8JDQgYHoHF0vPvFMYtxFTJuWaw==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.7.0.tgz", + "integrity": "sha512-SFtGpwmYN7RaWEAGTS4Rkc62ZV/qmQGg/tajr/7mfIkleuu8ro9Hlk6J+aA0x1YS4zlaZBtTcSaXM01QMiEV/A==", "requires": { "@babel/runtime": "^7.12.5", "array-tree-filter": "^2.1.0", "classnames": "^2.3.1", - "rc-select": "~14.0.0-alpha.23", - "rc-tree": "~5.4.3", + "rc-select": "~14.1.0", + "rc-tree": "~5.7.0", "rc-util": "^5.6.1" } }, @@ -13016,9 +14658,9 @@ } }, "rc-collapse": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.1.4.tgz", - "integrity": "sha512-WayrhswKMwuJab9xbqFxXTgV0m6X8uOPEO6zm/GJ5YJiJ/wIh/Dd2VtWeI06HYUEnTFv0HNcYv+zWbB+p6OD2A==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.3.1.tgz", + "integrity": "sha512-cOJfcSe3R8vocrF8T+PgaHDrgeA1tX+lwfhwSj60NX9QVRidsILIbRNDLD6nAzmcvVC5PWiIRiR4S1OobxdhCg==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "2.x", @@ -13028,63 +14670,63 @@ } }, "rc-dialog": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-8.6.0.tgz", - "integrity": "sha512-GSbkfqjqxpZC5/zc+8H332+q5l/DKUhpQr0vdX2uDsxo5K0PhvaMEVjyoJUTkZ3+JstEADQji1PVLVb/2bJeOQ==", + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-8.9.0.tgz", + "integrity": "sha512-Cp0tbJnrvPchJfnwIvOMWmJ4yjX3HWFatO6oBFD1jx8QkgsQCR0p8nUWAKdd3seLJhEC39/v56kZaEjwp9muoQ==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.6", "rc-motion": "^2.3.0", - "rc-util": "^5.6.1" + "rc-util": "^5.21.0" } }, "rc-drawer": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-4.4.3.tgz", - "integrity": "sha512-FYztwRs3uXnFOIf1hLvFxIQP9MiZJA+0w+Os8dfDh/90X7z/HqP/Yg+noLCIeHEbKln1Tqelv8ymCAN24zPcfQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-5.1.0.tgz", + "integrity": "sha512-pU3Tsn99pxGdYowXehzZbdDVE+4lDXSGb7p8vA9mSmr569oc2Izh4Zw5vLKSe/Xxn2p5MSNbLVqD4tz+pK6SOw==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.6", - "rc-util": "^5.7.0" + "rc-motion": "^2.6.1", + "rc-util": "^5.21.2" } }, "rc-dropdown": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-3.3.3.tgz", - "integrity": "sha512-UNe68VpvtrpU0CS4jh5hD4iGqzi4Pdp7uOya6+H3QIEZxe7K+Xs11BNjZm6W4MaL0jTmzUj+bxvnq5bP3rRoVQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.0.1.tgz", + "integrity": "sha512-OdpXuOcme1rm45cR0Jzgfl1otzmU4vuBVb+etXM8vcaULGokAKVpKlw8p6xzspG7jGd/XxShvq+N3VNEfk/l5g==", "requires": { - "@babel/runtime": "^7.10.1", + "@babel/runtime": "^7.18.3", "classnames": "^2.2.6", - "rc-trigger": "^5.0.4", + "rc-trigger": "^5.3.1", "rc-util": "^5.17.0" } }, "rc-field-form": { - "version": "1.26.2", - "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.26.2.tgz", - "integrity": "sha512-Q1QdpLAt/kxd119kJwGfFvn/ZIzjzTBJsCscy5k0z3g+eRMHkI0Exij6SE2D42N7FAzVkvuXTvzqWSiFGeer7g==", - "peer": true, + "version": "1.27.3", + "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.27.3.tgz", + "integrity": "sha512-HGqxHnmGQgkPApEcikV4qTg3BLPC82uB/cwBDftDt1pYaqitJfSl5TFTTUMKVEJVT5RqJ2Zi68ME1HmIMX2HAw==", "requires": { - "@babel/runtime": "^7.8.4", - "async-validator": "^4.0.2", + "@babel/runtime": "^7.18.0", + "async-validator": "^4.1.0", "rc-util": "^5.8.0" } }, "rc-image": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-5.2.5.tgz", - "integrity": "sha512-qUfZjYIODxO0c8a8P5GeuclYXZjzW4hV/5hyo27XqSFo1DmTCs2HkVeQObkcIk5kNsJtgsj1KoPThVsSc/PXOw==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-5.7.1.tgz", + "integrity": "sha512-QyMfdhoUfb5W14plqXSisaYwpdstcLYnB0MjX5ccIK2rydQM9sDPuekQWu500DDGR2dBaIF5vx9XbWkNFK17Fg==", "requires": { "@babel/runtime": "^7.11.2", "classnames": "^2.2.6", - "rc-dialog": "~8.6.0", + "rc-dialog": "~8.9.0", "rc-util": "^5.0.6" } }, "rc-input": { - "version": "0.0.1-alpha.6", - "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-0.0.1-alpha.6.tgz", - "integrity": "sha512-kgpmbxa9vp6kPLW7IP5/Lf6wuaMq+pUq+dPz98vIM58h4wkEKgBQlkMIg9OCEVQIiR8rEPEoe4dO2fc9R0aypQ==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-0.1.3.tgz", + "integrity": "sha512-FgW80AtNA3qTc++BPWXoBPVCGL7oSVbWxcEnBN51pBWpOqiJ6ta79EqtD/WI7k/N1SNqh+ie3GRfPmZhKOj6VQ==", "requires": { "@babel/runtime": "^7.11.1", "classnames": "^2.2.1", @@ -13092,32 +14734,32 @@ } }, "rc-input-number": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-7.3.4.tgz", - "integrity": "sha512-W9uqSzuvJUnz8H8vsVY4kx+yK51SsAxNTwr8SNH4G3XqQNocLVmKIibKFRjocnYX1RDHMND9FFbgj2h7E7nvGA==", + "version": "7.3.9", + "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-7.3.9.tgz", + "integrity": "sha512-u0+miS+SATdb6DtssYei2JJ1WuZME+nXaG6XGtR8maNyW5uGDytfDu60OTWLQEb0Anv/AcCzehldV8CKmKyQfA==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.5", - "rc-util": "^5.9.8" + "rc-util": "^5.23.0" } }, "rc-mentions": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-1.6.5.tgz", - "integrity": "sha512-CUU4+q+awG2pA0l/tG2kPB2ytWbKQUkFxVeKwacr63w7crE/yjfzrFXxs/1fxhyEbQUWdAZt/L25QBieukYQ5w==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-1.10.0.tgz", + "integrity": "sha512-oMlYWnwXSxP2NQVlgxOTzuG/u9BUc3ySY78K3/t7MNhJWpZzXTao+/Bic6tyZLuNCO89//hVQJBdaR2rnFQl6Q==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.6", - "rc-menu": "~9.3.2", - "rc-textarea": "^0.3.0", + "rc-menu": "~9.6.0", + "rc-textarea": "^0.4.0", "rc-trigger": "^5.0.4", - "rc-util": "^5.0.1" + "rc-util": "^5.22.5" } }, "rc-menu": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.3.2.tgz", - "integrity": "sha512-h3m45oY1INZyqphGELkdT0uiPnFzxkML8m0VMhJnk2fowtqfiT7F5tJLT3znEVaPIY80vMy1bClCkgq8U91CzQ==", + "version": "9.6.4", + "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.6.4.tgz", + "integrity": "sha512-6DiNAjxjVIPLZXHffXxxcyE15d4isRL7iQ1ru4MqYDH2Cqc5bW96wZOdMydFtGLyDdnmEQ9jVvdCE9yliGvzkw==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "2.x", @@ -13129,30 +14771,30 @@ } }, "rc-motion": { - "version": "2.4.9", - "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.4.9.tgz", - "integrity": "sha512-lrIpBQQ5gIDVedaubnhXuTjC3zpW7HvC/34KyvcHlf6fBjuBlwv45PbonFhmk4Rgu7gLQYrKoMGgFVXqxxyLCw==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.6.2.tgz", + "integrity": "sha512-4w1FaX3dtV749P8GwfS4fYnFG4Rb9pxvCYPc/b2fw1cmlHJWNNgOFIz7ysiD+eOrzJSvnLJWlNQQncpNMXwwpg==", "requires": { "@babel/runtime": "^7.11.1", "classnames": "^2.2.1", - "rc-util": "^5.19.2" + "rc-util": "^5.21.0" } }, "rc-notification": { - "version": "4.5.7", - "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-4.5.7.tgz", - "integrity": "sha512-zhTGUjBIItbx96SiRu3KVURcLOydLUHZCPpYEn1zvh+re//Tnq/wSxN4FKgp38n4HOgHSVxcLEeSxBMTeBBDdw==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-4.6.0.tgz", + "integrity": "sha512-xF3MKgIoynzjQAO4lqsoraiFo3UXNYlBfpHs0VWvwF+4pimen9/H1DYLN2mfRWhHovW6gRpla73m2nmyIqAMZQ==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "2.x", "rc-motion": "^2.2.0", - "rc-util": "^5.0.1" + "rc-util": "^5.20.1" } }, "rc-overflow": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.2.4.tgz", - "integrity": "sha512-nIeelyYfdS+mQBK1++FisLZEvZ8xVAzC+duG+TC4TmqNN+kTHraiGntV9/zxDGA1ruyQ91YRJ549JjFodCBnsw==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.2.8.tgz", + "integrity": "sha512-QJ0UItckWPQ37ZL1dMEBAdY1dhfTXFL9k6oTTcyydVwoUNMnMqCGqnRNA98axSr/OeDKqR6DVFyi8eA5RQI/uQ==", "requires": { "@babel/runtime": "^7.11.1", "classnames": "^2.2.1", @@ -13161,18 +14803,18 @@ } }, "rc-pagination": { - "version": "3.1.15", - "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-3.1.15.tgz", - "integrity": "sha512-4L3fot8g4E+PjWEgoVGX0noFCg+8ZFZmeLH4vsnZpB3O2T2zThtakjNxG+YvSaYtyMVT4B+GLayjKrKbXQpdAg==", + "version": "3.1.17", + "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-3.1.17.tgz", + "integrity": "sha512-/BQ5UxcBnW28vFAcP2hfh+Xg15W0QZn8TWYwdCApchMH1H0CxiaUUcULP8uXcFM1TygcdKWdt3JqsL9cTAfdkQ==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.1" } }, "rc-picker": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-2.6.7.tgz", - "integrity": "sha512-+P2Grt0r2kmCkw2XTp9ew3zTCwBCFEOQLd5BYs+hFaGDSSZwEWJtlbGXAGqWnAUMFx6JrCsKYkDKXDxAWlRz3A==", + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-2.6.11.tgz", + "integrity": "sha512-INJ7ULu+Kj4UgqbcqE8Q+QpMw55xFf9kkyLBHJFk0ihjJpAV4glialRfqHE7k4KX2BWYPQfpILwhwR14x2EiRQ==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.1", @@ -13185,9 +14827,9 @@ } }, "rc-progress": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-3.2.4.tgz", - "integrity": "sha512-M9WWutRaoVkPUPIrTpRIDpX0SPSrVHzxHdCRCbeoBFrd9UFWTYNWRlHsruJM5FH1AZI+BwB4wOJUNNylg/uFSw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-3.3.3.tgz", + "integrity": "sha512-MDVNVHzGanYtRy2KKraEaWeZLri2ZHWIRyaE1a9MQ2MuJ09m+Wxj5cfcaoaR6z5iRpHpA59YeUxAlpML8N4PJw==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.6", @@ -13215,10 +14857,21 @@ "resize-observer-polyfill": "^1.5.1" } }, + "rc-segmented": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.1.0.tgz", + "integrity": "sha512-hUlonro+pYoZcwrH6Vm56B2ftLfQh046hrwif/VwLIw1j3zGt52p5mREBwmeVzXnSwgnagpOpfafspzs1asjGw==", + "requires": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-motion": "^2.4.4", + "rc-util": "^5.17.0" + } + }, "rc-select": { - "version": "14.0.6", - "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.0.6.tgz", - "integrity": "sha512-HMb2BwfTvBxMmIWTR/afP4bcRJLbVKFSBW/VFfL5Z+kdV2XlrYdlliK2uHY7pRRvW16PPGwmOwGfV+eoulPINw==", + "version": "14.1.13", + "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.1.13.tgz", + "integrity": "sha512-WMEsC3gTwA1dbzWOdVIXDmWyidYNLq68AwvvUlRROw790uGUly0/vmqDozXrIr0QvN/A3CEULx12o+WtLCAefg==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "2.x", @@ -13262,34 +14915,35 @@ } }, "rc-table": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.23.2.tgz", - "integrity": "sha512-opc2IBJOetsPSdNI+u1Lh9yY4Ks+EMgo1oJzZN+yIV4fRcgP81tHtxdPOVvXPFI4rUMO8CKnmHbGPU7jxMRAeg==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.26.0.tgz", + "integrity": "sha512-0cD8e6S+DTGAt5nBZQIPFYEaIukn17sfa5uFL98faHlH/whZzD8ii3dbFL4wmUDEL4BLybhYop+QUfZJ4CPvNQ==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.5", "rc-resize-observer": "^1.1.0", - "rc-util": "^5.14.0", + "rc-util": "^5.22.5", "shallowequal": "^1.1.0" } }, "rc-tabs": { - "version": "11.10.8", - "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-11.10.8.tgz", - "integrity": "sha512-uK+x+eJ8WM4jiXoqGa+P+JUQX2Wlkj9f0o/5dyOw42B6YLnHJN80uTVcCeAmtA1N0xjPW0GNSZvUm4SU3jAYpw==", + "version": "12.2.1", + "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-12.2.1.tgz", + "integrity": "sha512-09pVv4kN8VFqp6THceEmxOW8PAShQC08hrroeVYP4Y8YBFaP1PIWdyFL01czcbyz5YZFj9flZ7aljMaAl0jLVg==", "requires": { "@babel/runtime": "^7.11.2", "classnames": "2.x", - "rc-dropdown": "^3.2.0", - "rc-menu": "~9.3.2", + "rc-dropdown": "~4.0.0", + "rc-menu": "~9.6.0", + "rc-motion": "^2.6.2", "rc-resize-observer": "^1.0.0", "rc-util": "^5.5.0" } }, "rc-textarea": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-0.3.7.tgz", - "integrity": "sha512-yCdZ6binKmAQB13hc/oehh0E/QRwoPP1pjF21aHBxlgXO3RzPF6dUu4LG2R4FZ1zx/fQd2L1faktulrXOM/2rw==", + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-0.4.5.tgz", + "integrity": "sha512-WHeJRgUlloNyVgTsItMrIXwMhU6P3NmrUDkxX+JRwEpJjECsKtZNlNcXe9pHNLCaYQ3Z1cVCfsClhgDDgJ2kFQ==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.1", @@ -13299,44 +14953,45 @@ } }, "rc-tooltip": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-5.1.1.tgz", - "integrity": "sha512-alt8eGMJulio6+4/uDm7nvV+rJq9bsfxFDCI0ljPdbuoygUscbsMYb6EQgwib/uqsXQUvzk+S7A59uYHmEgmDA==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-5.2.2.tgz", + "integrity": "sha512-jtQzU/18S6EI3lhSGoDYhPqNpWajMtS5VV/ld1LwyfrDByQpYmw/LW6U7oFXXLukjfDHQ7Ju705A82PRNFWYhg==", "requires": { "@babel/runtime": "^7.11.2", + "classnames": "^2.3.1", "rc-trigger": "^5.0.0" } }, "rc-tree": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.4.4.tgz", - "integrity": "sha512-2qoObRgp31DBXmVzMJmo4qmwP20XEa4hR3imWQtRPcgN3pmljW3WKFmZRrYdOFHz7CyTnRsFZR065bBkIoUpiA==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.7.0.tgz", + "integrity": "sha512-F+Ewkv/UcutshnVBMISP+lPdHDlcsL+YH/MQDVWbk+QdkfID7vXiwrHMEZn31+2Rbbm21z/HPceGS8PXGMmnQg==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "2.x", "rc-motion": "^2.0.1", "rc-util": "^5.16.1", - "rc-virtual-list": "^3.4.2" + "rc-virtual-list": "^3.4.8" } }, "rc-tree-select": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.1.5.tgz", - "integrity": "sha512-OXAwCFO0pQmb48NcjUJtiX6rp4FroCXMfzqPmuVVoBGBV/uwO1TPyb+uBZ2/972zkCA8u4je5M5Qx51sL8y7jg==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.5.3.tgz", + "integrity": "sha512-gv8KyC6J7f9e50OkGk1ibF7v8vL+iaBnA8Ep/EVlMma2/tGdBQXO9xIvPjX8eQrZL5PjoeTUndNPM3cY3721ng==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "2.x", - "rc-select": "~14.0.0-alpha.8", - "rc-tree": "~5.4.3", + "rc-select": "~14.1.0", + "rc-tree": "~5.7.0", "rc-util": "^5.16.1" } }, "rc-trigger": { - "version": "5.2.15", - "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-5.2.15.tgz", - "integrity": "sha512-VxZWqCObtUOzs9V9Be0dDA2JGchriDpvQaJpsCI2EQ4+KWHIvjFz6Ziina4uxK5drRsn0RnBi7nngmTl9j/F7Q==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-5.3.1.tgz", + "integrity": "sha512-5gaFbDkYSefZ14j2AdzucXzlWgU2ri5uEjkHvsf1ynRhdJbKxNOnw4PBZ9+FVULNGFiDzzlVF8RJnR9P/xrnKQ==", "requires": { - "@babel/runtime": "^7.11.2", + "@babel/runtime": "^7.18.3", "classnames": "^2.2.6", "rc-align": "^4.0.0", "rc-motion": "^2.0.0", @@ -13354,19 +15009,19 @@ } }, "rc-util": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.20.1.tgz", - "integrity": "sha512-2IEyErPAYl0Up5gBu71e8IkOs+/SL9XRUvnGhtsr7IHlXLx2OsbQKTDpWacJbzLCmNcgJylDGj1kiklx+zagRA==", + "version": "5.24.4", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.24.4.tgz", + "integrity": "sha512-2a4RQnycV9eV7lVZPEJ7QwJRPlZNc06J7CwcwZo4vIHr3PfUqtYgl1EkUV9ETAc6VRRi8XZOMFhYG63whlIC9Q==", "requires": { - "@babel/runtime": "^7.12.5", + "@babel/runtime": "^7.18.3", "react-is": "^16.12.0", "shallowequal": "^1.1.0" } }, "rc-virtual-list": { - "version": "3.4.6", - "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.4.6.tgz", - "integrity": "sha512-wMJ7Bl+AxgIDojp0VxuQxjpNulKodwxGXSsTyxA9Mwzwemj5vKAgTbkPT64ZW5ORf8FOQAaPRlMiTADrPEo3sQ==", + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.4.10.tgz", + "integrity": "sha512-Jv0cgJxJ+8F/YViW8WGs/jQF2rmT8RUcJ5uDJs5MOFLTYLAvCpM/xU+Zu6EpCun50fmovhXiItQctcfE2UY3Aw==", "requires": { "classnames": "^2.2.6", "rc-resize-observer": "^1.0.0", @@ -13418,6 +15073,35 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "react-markdown": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.3.tgz", + "integrity": "sha512-We36SfqaKoVNpN1QqsZwWSv/OZt5J15LNgTLWynwAN5b265hrQrsjMtlRNwUvS+YyR3yDM8HpTNc4pK9H/Gc0A==", + "requires": { + "@types/hast": "^2.0.0", + "@types/prop-types": "^15.0.0", + "@types/unist": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^2.0.0", + "prop-types": "^15.0.0", + "property-information": "^6.0.0", + "react-is": "^18.0.0", + "remark-parse": "^10.0.0", + "remark-rehype": "^10.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.3.0", + "unified": "^10.0.0", + "unist-util-visit": "^4.0.0", + "vfile": "^5.0.0" + }, + "dependencies": { + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + } + } + }, "react-router": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.3.0.tgz", @@ -13554,6 +15238,27 @@ "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", "dev": true }, + "remark-parse": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", + "integrity": "sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==", + "requires": { + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "unified": "^10.0.0" + } + }, + "remark-rehype": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-10.1.0.tgz", + "integrity": "sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==", + "requires": { + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-to-hast": "^12.1.0", + "unified": "^10.0.0" + } + }, "renderkid": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", @@ -13640,6 +15345,14 @@ "queue-microtask": "^1.2.2" } }, + "sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "requires": { + "mri": "^1.1.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -13929,6 +15642,11 @@ } } }, + "space-separated-tokens": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.1.tgz", + "integrity": "sha512-ekwEbFp5aqSPKaqeY1PGrlGQxPNaq+Cnx4+bE2D8sciBQrHpbwoBbawqTN2+6jPs9IdWxxiUcN0K2pkczD3zmw==" + }, "spdy": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", @@ -13982,7 +15700,7 @@ "string-convert": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", - "integrity": "sha1-aYLMMEn7tM2F+LJFaLnZvznu/5c=" + "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==" }, "strip-ansi": { "version": "6.0.1", @@ -14006,6 +15724,14 @@ "dev": true, "requires": {} }, + "style-to-object": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", + "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", + "requires": { + "inline-style-parser": "0.1.1" + } + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -14034,14 +15760,14 @@ "dev": true }, "terser": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.12.1.tgz", - "integrity": "sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ==", + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", + "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", "dev": true, "requires": { + "@jridgewell/source-map": "^0.3.2", "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "dependencies": { @@ -14050,12 +15776,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true - }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true } } }, @@ -14128,6 +15848,16 @@ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true }, + "trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==" + }, + "trough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", + "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==" + }, "tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", @@ -14172,6 +15902,80 @@ "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", "dev": true }, + "unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "requires": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "dependencies": { + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" + } + } + }, + "unist-builder": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-3.0.0.tgz", + "integrity": "sha512-GFxmfEAa0vi9i5sd0R2kcrI9ks0r82NasRq5QHh2ysGngrc6GiqD5CDf1FjPenY4vApmFASBIIlk/jj5J5YbmQ==", + "requires": { + "@types/unist": "^2.0.0" + } + }, + "unist-util-generated": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.0.tgz", + "integrity": "sha512-TiWE6DVtVe7Ye2QxOVW9kqybs6cZexNwTwSMVgkfjEReqy/xwGpAXb99OxktoWwmL+Z+Epb0Dn8/GNDYP1wnUw==" + }, + "unist-util-is": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.1.1.tgz", + "integrity": "sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==" + }, + "unist-util-position": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-4.0.3.tgz", + "integrity": "sha512-p/5EMGIa1qwbXjA+QgcBXaPWjSnZfQ2Sc3yBEEfgPwsEmJd8Qh+DSk3LGnmOM4S1bY2C0AjmMnB8RuEYxpPwXQ==", + "requires": { + "@types/unist": "^2.0.0" + } + }, + "unist-util-stringify-position": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz", + "integrity": "sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==", + "requires": { + "@types/unist": "^2.0.0" + } + }, + "unist-util-visit": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.1.tgz", + "integrity": "sha512-n9KN3WV9k4h1DxYR1LoajgN93wpEi/7ZplVe02IoB4gH5ctI1AaF2670BLHQYbwj+pY83gFtyeySFiyMHJklrg==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + } + }, + "unist-util-visit-parents": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.1.tgz", + "integrity": "sha512-gks4baapT/kNRaWxuGkl5BIhoanZo7sC/cUT/JToSRNL1dYoXRFl75d++NkjYk4TAu2uv2Px+l8guMajogeuiw==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + } + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -14228,12 +16032,43 @@ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true }, + "uvu": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", + "requires": { + "dequal": "^2.0.0", + "diff": "^5.0.0", + "kleur": "^4.0.3", + "sade": "^1.7.3" + } + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", "dev": true }, + "vfile": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.5.tgz", + "integrity": "sha512-U1ho2ga33eZ8y8pkbQLH54uKqGhFJ6GYIHnnG5AhRpAh3OWjkrRHKa/KogbmQn8We+c0KVV3rTOgR9V/WowbXQ==", + "requires": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + } + }, + "vfile-message": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.2.tgz", + "integrity": "sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA==", + "requires": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + } + }, "virtuallist-antd": { "version": "0.7.4-beta.0", "resolved": "https://registry.npmjs.org/virtuallist-antd/-/virtuallist-antd-0.7.4-beta.0.tgz", @@ -14551,20 +16386,20 @@ "requires": {} }, "xterm": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/xterm/-/xterm-4.18.0.tgz", - "integrity": "sha512-JQoc1S0dti6SQfI0bK1AZvGnAxH4MVw45ZPFSO6FHTInAiau3Ix77fSxNx3mX4eh9OL4AYa8+4C8f5UvnSfppQ==" + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.0.0.tgz", + "integrity": "sha512-tmVsKzZovAYNDIaUinfz+VDclraQpPUnAME+JawosgWRMphInDded/PuY0xmU5dOhyeYZsI0nz5yd8dPYsdLTA==" }, "xterm-addon-fit": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.5.0.tgz", - "integrity": "sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.6.0.tgz", + "integrity": "sha512-9/7A+1KEjkFam0yxTaHfuk9LEvvTSBi0PZmEkzJqgafXPEXL9pCMAVV7rB09sX6ATRDXAdBpQhZkhKj7CGvYeg==", "requires": {} }, "xterm-addon-web-links": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/xterm-addon-web-links/-/xterm-addon-web-links-0.5.1.tgz", - "integrity": "sha512-dBjbOIrCNmxAcUQkkSrKj9BM6yLpmqUpZ9SOCUuZe/sznPl4d8OBZQClK7VcdZ0vf0+5i5Fce2rUUrew/XTZTg==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/xterm-addon-web-links/-/xterm-addon-web-links-0.7.0.tgz", + "integrity": "sha512-6PqoqzzPwaeSq22skzbvyboDvSnYk5teUYEoKBwMYvhbkwOQkemZccjWHT5FnNA8o1aInTc4PRYAl4jjPucCKA==", "requires": {} }, "yallist": { diff --git a/web/package.json b/web/package.json index b3bf9bf..ed9193f 100644 --- a/web/package.json +++ b/web/package.json @@ -14,9 +14,9 @@ "@ant-design/pro-layout": "^6.23.0", "@ant-design/pro-table": "^2.45.0", "ace-builds": "^1.5.3", - "antd": "^4.16.8", + "antd": "^4.23.6", "axios": "^0.26.1", - "crypto-js": "^4.1.1", + "crc-32": "^1.2.2", "dayjs": "^1.10.6", "i18next": "^21.6.15", "lodash": "^4.17.21", @@ -25,13 +25,14 @@ "react-ace": "^10.1.0", "react-dom": "^17.0.2", "react-draggable": "^4.4.5", + "react-markdown": "^8.0.3", "react-router": "^6.2.2", "react-router-dom": "^6.2.2", "virtuallist-antd": "^0.7.4-beta.0", "wcwidth": "^1.0.1", - "xterm": "^4.18.0", - "xterm-addon-fit": "^0.5.0", - "xterm-addon-web-links": "^0.5.1" + "xterm": "^5.0.0", + "xterm-addon-fit": "^0.6.0", + "xterm-addon-web-links": "^0.7.0" }, "devDependencies": { "@babel/core": "^7.17.9", diff --git a/web/src/components/desktop.js b/web/src/components/desktop.js index 676c524..fc909a5 100644 --- a/web/src/components/desktop.js +++ b/web/src/components/desktop.js @@ -1,8 +1,7 @@ import React, {useCallback, useEffect, useState} from 'react'; -import {encrypt, decrypt, formatSize, genRandHex, getBaseURL, translate} from "../utils/utils"; +import {encrypt, decrypt, formatSize, genRandHex, getBaseURL, translate, hex2ua, ua2hex} from "../utils/utils"; import i18n from "../locale/locale"; import DraggableModal from "./modal"; -import CryptoJS from "crypto-js"; import {Button, message} from "antd"; import {FullscreenOutlined, ReloadOutlined} from "@ant-design/icons"; @@ -20,15 +19,15 @@ function ScreenModal(props) { const [bandwidth, setBandwidth] = useState(0); const [fps, setFps] = useState(0); const canvasRef = useCallback((e) => { - if (e && props.visible && !conn) { + if (e && props.open && !conn) { canvas = e; initCanvas(canvas); construct(canvas); } }, [props]); useEffect(() => { - if (props.visible) { - secret = CryptoJS.enc.Hex.parse(genRandHex(32)); + if (props.open) { + secret = hex2ua(genRandHex(32)); } else { if (ws && conn) { clearInterval(ticker); @@ -36,7 +35,7 @@ function ScreenModal(props) { conn = false; } } - }, [props.visible, props.device]); + }, [props.open, props.device]); function initCanvas() { if (!canvas) return; @@ -47,7 +46,7 @@ function ScreenModal(props) { if (ws !== null && conn) { ws.close(); } - ws = new WebSocket(getBaseURL(true, `api/device/desktop?device=${props.device.id}&secret=${secret}`)); + ws = new WebSocket(getBaseURL(true, `api/device/desktop?device=${props.device.id}&secret=${ua2hex(secret)}`)); ws.binaryType = 'arraybuffer'; ws.onopen = () => { conn = true; @@ -79,9 +78,9 @@ function ScreenModal(props) { ticks++; if (ticks > 10 && conn) { ticks = 0; - ws.send(encrypt({ + sendData({ act: 'DESKTOP_PING' - }, secret)); + }); } }, 1000); } @@ -101,16 +100,16 @@ function ScreenModal(props) { } catch {} } function refresh() { - if (canvas && props.visible) { + if (canvas && props.open) { if (!conn) { canvas.width = 1920; canvas.height = 1080; initCanvas(canvas); construct(canvas); } else { - ws.send(encrypt({ + sendData({ act: 'DESKTOP_SHOT' - }, secret)); + }); } } } @@ -124,8 +123,8 @@ function ScreenModal(props) { return; } if (op === 2) { - let width = dv.getUint16(1, false); - let height = dv.getUint16(3, false); + let width = dv.getUint16(3, false); + let height = dv.getUint16(5, false); if (width === 0 || height === 0) return; canvas.width = width; canvas.height = height; @@ -135,12 +134,13 @@ function ScreenModal(props) { bytes += ab.byteLength; let offset = 1; while (offset < ab.byteLength) { - let it = dv.getUint16(offset + 0, false); // image type - let il = dv.getUint16(offset + 2, false); // image length + let bl = dv.getUint16(offset + 0, false); // body length + let it = dv.getUint16(offset + 2, false); // image type let dx = dv.getUint16(offset + 4, false); // image block x let dy = dv.getUint16(offset + 6, false); // image block y let bw = dv.getUint16(offset + 8, false); // image block width let bh = dv.getUint16(offset + 10, false); // image block height + let il = bl - 10; // image length offset += 12; updateImage(ab.slice(offset, offset + il), it, dx, dy, bw, bh, canvasCtx); offset += il; @@ -173,6 +173,17 @@ function ScreenModal(props) { } } + function sendData(data) { + if (conn) { + let body = encrypt(data, secret); + let buffer = new Uint8Array(body.length + 8); + buffer.set(new Uint8Array([34, 22, 19, 17, 20, 3]), 0); + buffer.set(new Uint8Array([body.length >> 8, body.length & 0xFF]), 6); + buffer.set(body, 8); + ws.send(buffer); + } + } + return ( .ant-progress-outer > .ant-progress-inner { - border-radius: 0 !important; -} + .editor-modal, .editor-modal > .ant-modal-content { top: 0; @@ -43,3 +36,8 @@ a { .editor-modal > .ant-modal-content > .ant-modal-body { height: calc(100% - 110px); } + +.file-row { + user-select: none; + cursor: pointer; +} diff --git a/web/src/components/explorer.js b/web/src/components/explorer.js index d56280a..2f42889 100644 --- a/web/src/components/explorer.js +++ b/web/src/components/explorer.js @@ -1,30 +1,23 @@ import React, {useEffect, useMemo, useRef, useState} from "react"; +import ProTable, {TableDropdown} from "@ant-design/pro-table"; import { - Alert, - Breadcrumb, - Button, - Dropdown, - Image, - Menu, - message, - Modal, - Popconfirm, - Progress, - Space, - Spin + Alert, Breadcrumb, Button, + Dropdown, Image, Menu, + message, Modal, Popconfirm, + Progress, Space, Spin, Typography } from "antd"; -import ProTable, {TableDropdown} from "@ant-design/pro-table"; -import {catchBlobReq, formatSize, orderCompare, post, preventClose, request, waitTime} from "../utils/utils"; +import { + catchBlobReq, formatSize, + orderCompare, post, request, + preventClose, waitTime +} from "../utils/utils"; import dayjs from "dayjs"; import i18n from "../locale/locale"; import {VList} from "virtuallist-antd"; import { - CloseOutlined, FullscreenOutlined, - HomeOutlined, - LoadingOutlined, - QuestionCircleOutlined, - ReloadOutlined, - UploadOutlined + CloseOutlined, HomeOutlined, + LoadingOutlined, QuestionCircleOutlined, + ReloadOutlined, UploadOutlined } from "@ant-design/icons"; import axios from "axios"; import Qs from "qs"; @@ -68,7 +61,7 @@ function FileBrowser(props) { }, { key: 'Time', - title: i18n.t('EXPLORER.MODIFY_TIME'), + title: i18n.t('EXPLORER.DATE_MODIFIED'), dataIndex: 'time', ellipsis: true, width: 100, @@ -94,7 +87,8 @@ function FileBrowser(props) { const tableRef = useRef(); const virtualTable = useMemo(() => { return VList({ - height: 300 + height: 300, + vid: 'file-table', }) }, []); const alertOptionRenderer = () => ( @@ -116,11 +110,11 @@ function FileBrowser(props) { position = '/'; setPath(`/`); } - if (props.visible) { + if (props.open) { fileList = []; setLoading(false); } - }, [props.device, props.visible]); + }, [props.device, props.open]); function renderOperation(file) { let menus = [ @@ -269,7 +263,7 @@ function FileBrowser(props) { return; } } - document.getElementById('uploader').click(); + document.getElementById('file-uploader').click(); } function onFileChange(e) { let file = e.target.files[0]; @@ -472,10 +466,10 @@ function FileBrowser(props) { onClick={uploadFile} /> @@ -626,7 +621,7 @@ function TextEditor(props) { } catch (e) { require('ace-builds/src-min-noconflict/mode-text'); } - setVisible(true); + setOpen(true); setFileContent(props.content); setEditorMode(fileMode); } @@ -662,7 +657,7 @@ function TextEditor(props) { function onForceCancel(reload) { setCancelConfirm(false); setTimeout(() => { - setVisible(false); + setOpen(false); setFileContent(''); window.onbeforeunload = null; props.onCancel(reload); @@ -676,7 +671,7 @@ function TextEditor(props) { if (fileStatus === 1) { setCancelConfirm(true); } else { - setVisible(false); + setOpen(false); setFileContent(''); window.onbeforeunload = null; props.onCancel(fileStatus === 2); @@ -718,7 +713,7 @@ function TextEditor(props) { title={props.file} mask={false} keyboard={false} - visible={visible} + open={open} maskClosable={false} className='editor-modal' closeIcon={loading ? } /> : } @@ -771,7 +766,7 @@ function TextEditor(props) { }]} value={fileContent} onChange={val => { - if (!visible) return; + if (!open) return; if (val.length === fileContent.length) { if (val === fileContent) return; } @@ -788,7 +783,7 @@ function TextEditor(props) { /> { setStatus(0); if (props.file) { - setVisible(true); + setOpen(true); setPercent(0); } }, [props.file]); @@ -906,19 +901,19 @@ function FileUploader(props) { abortController = null; window.onbeforeunload = null; setTimeout(() => { - setVisible(false); + setOpen(false); if (uploadStatus === 2) { props.onSuccess(); } else { - props.onCanel(); + props.onCancel(); } }, 1500); }); } function onCancel() { if (status === 0) { - setVisible(false); - setTimeout(props.onCanel, 300); + setOpen(false); + setTimeout(props.onCancel, 300); return; } if (status === 1) { @@ -935,8 +930,8 @@ function FileUploader(props) { return; } setTimeout(() => { - setVisible(false); - setTimeout(props.onCanel, 300); + setOpen(false); + setTimeout(props.onCancel, 300); }, 1500); } @@ -953,41 +948,50 @@ function FileUploader(props) { default: return i18n.t('EXPLORER.UPLOAD'); } - } return ( 1}} + onCancel={onCancel} + onOk={onConfirm} width={550} > - <> +
{getDescription()} - {props.file.name + ` (${formatSize(props.file.size)})`} - + + {props.file.name} + + + {'('+formatSize(props.file.size)+')'} + +
diff --git a/web/src/components/modal.js b/web/src/components/modal.js index 2508e99..001b4cb 100644 --- a/web/src/components/modal.js +++ b/web/src/components/modal.js @@ -10,11 +10,11 @@ function DraggableModal(props) { bottom: 0, right: 0, }); - const draggleRef = useRef(null); + const draggableRef = useRef(null); const onStart = (_event, uiData) => { const { clientWidth, clientHeight } = window.document.documentElement; - const targetRect = draggleRef.current?.getBoundingClientRect(); + const targetRect = draggableRef.current?.getBoundingClientRect(); if (!targetRect || disabled) { return; } @@ -55,7 +55,7 @@ function DraggableModal(props) { bounds={bounds} onStart={(event, uiData) => onStart(event, uiData)} > -
{modal}
+
{modal}
)} {...props} diff --git a/web/src/components/procmgr.js b/web/src/components/procmgr.js index 0f8b43f..53bc555 100644 --- a/web/src/components/procmgr.js +++ b/web/src/components/procmgr.js @@ -47,10 +47,10 @@ function ProcessMgr(props) { }) }, []); useEffect(() => { - if (props.visible) { + if (props.open) { setLoading(false); } - }, [props.device, props.visible]); + }, [props.device, props.open]); function renderOperation(proc) { return [ diff --git a/web/src/components/runner.js b/web/src/components/runner.js index c9c9ae0..fd15ae6 100644 --- a/web/src/components/runner.js +++ b/web/src/components/runner.js @@ -24,8 +24,8 @@ function Runner(props) { title={i18n.t('RUNNER.TITLE')} width={380} onFinish={onFinish} - onVisibleChange={visible => { - if (!visible) props.onCancel(); + onVisibleChange={open => { + if (!open) props.onCancel(); }} submitter={{ render: (_, elems) => elems.pop() diff --git a/web/src/components/terminal.js b/web/src/components/terminal.js index 11fbf23..08e7413 100644 --- a/web/src/components/terminal.js +++ b/web/src/components/terminal.js @@ -1,48 +1,62 @@ -import React, {createRef, useCallback} from "react"; +import React, {createRef, useCallback, useState} from "react"; import {Button, Dropdown, Menu, message, Space} from "antd"; import {Terminal} from "xterm"; import {WebLinksAddon} from "xterm-addon-web-links"; import {FitAddon} from "xterm-addon-fit"; import debounce from 'lodash/debounce'; -import CryptoJS from 'crypto-js'; import wcwidth from 'wcwidth'; import "xterm/css/xterm.css"; import i18n from "../locale/locale"; -import {encrypt, decrypt, ab2str, genRandHex, getBaseURL, hex2buf, translate} from "../utils/utils"; +import { + decrypt, encrypt, genRandHex, getBaseURL, + hex2ua, str2hex, str2ua, translate, + ua2hex, ua2str +} from "../utils/utils"; import DraggableModal from "./modal"; +const Zmodem = require("../vendors/zmodem.js/zmodem"); -let ws = null; +let zsentry = null; +let zsession = null; + +let webLinks = null; let fit = null; let term = null; let termEv = null; +let secret = null; + +let ws = null; let ctrl = false; let conn = false; let ticker = 0; +let buffer = {content: '', output: ''}; + function TerminalModal(props) { let os = props.device.os; let extKeyRef = createRef(); - let secret = CryptoJS.enc.Hex.parse(genRandHex(32)); let termRef = useCallback(e => { if (e !== null) { termRef.current = e; - if (props.visible) { - ctrl = false; + if (props.open) { + secret = hex2ua(genRandHex(32)); + fit = new FitAddon(); + webLinks = new WebLinksAddon(); term = new Terminal({ convertEol: true, + allowProposedApi: true, allowTransparency: false, cursorBlink: true, cursorStyle: "block", fontFamily: "Hack, monospace", fontSize: 16, logLevel: "off", - }) - fit = new FitAddon(); + }); termEv = initialize(null); term.loadAddon(fit); - term.loadAddon(new WebLinksAddon()); term.open(termRef.current); fit.fit(); term.clear(); + term.loadAddon(webLinks); + window.onresize = onResize; ticker = setInterval(() => { if (conn) sendData({act: 'PING'}); @@ -51,10 +65,15 @@ function TerminalModal(props) { doResize(); } } - }, [props.visible]); + }, [props.open]); function afterClose() { clearInterval(ticker); + if (zsession) { + zsession._last_header_name = 'ZRINIT'; + zsession.close(); + zsession = null; + } if (conn) { sendData({act: 'TERMINAL_KILL'}); ws.onclose = null; @@ -64,79 +83,129 @@ function TerminalModal(props) { termEv = null; fit?.dispose(); fit = null; + webLinks?.dispose(); + webLinks = null; + zsentry = null; term?.dispose(); term = null; ws = null; conn = false; + ctrl = false; } function initialize(ev) { ev?.dispose(); - let buffer = { content: '', output: '' }; + buffer = {content: '', output: ''}; let termEv = null; // Windows doesn't support pty, so we still use traditional way. // And we need to handle arrow events manually. if (os === 'windows') { - termEv = term.onData(onWindowsInput.call(this, buffer)); + termEv = term.onData(onWindowsInput(buffer)); } else { - termEv = term.onData(onUnixOSInput.call(this, buffer)); + initZmodem(); + termEv = term.onData(onUnixOSInput(buffer)); } - ws = new WebSocket(getBaseURL(true, `api/device/terminal?device=${props.device.id}&secret=${secret}`)); + ws = new WebSocket(getBaseURL(true, `api/device/terminal?device=${props.device.id}&secret=${ua2hex(secret)}`)); ws.binaryType = 'arraybuffer'; ws.onopen = () => { conn = true; } ws.onmessage = (e) => { - let data = decrypt(e.data, secret); + onWsMessage(e.data, buffer); + } + ws.onclose = (e) => { + if (conn) { + conn = false; + term.write(`\n${i18n.t('COMMON.DISCONNECTED')}\n`); + secret = hex2ua(genRandHex(32)); + if (zsession !== null) { + zsession._last_header_name = 'ZRINIT'; + zsession.close(); + zsession = null; + } + } + } + ws.onerror = (e) => { + console.error(e); + if (conn) { + conn = false; + term.write(`\n${i18n.t('COMMON.DISCONNECTED')}\n`); + secret = hex2ua(genRandHex(32)); + if (zsession !== null) { + zsession._last_header_name = 'ZRINIT'; + zsession.close(); + zsession = null; + } + } else { + term.write(`\n${i18n.t('COMMON.CONNECTION_FAILED')}\n`); + } + } + return termEv; + } + function onWsMessage(data) { + data = new Uint8Array(data); + if (data[0] === 34 && data[1] === 22 && data[2] === 19 && data[3] === 17 && data[4] === 21 && data[5] === 0) { + data = data.slice(8); + if (zsentry === null) { + onOutput(ua2str(data)); + } else { + try { + zsentry.consume(data); + } catch (e) { + console.error(e); + } + } + } else { + data = decrypt(data, secret); try { data = JSON.parse(data); } catch (_) {} if (conn) { if (data?.act === 'TERMINAL_OUTPUT') { - data = ab2str(hex2buf(data?.data?.output)); - if (buffer.output.length > 0) { - data = buffer.output + data; - buffer.output = ''; - } - if (buffer.content.length > 0) { - if (data.length > buffer.content.length) { - if (data.startsWith(buffer.content)) { - data = data.substring(buffer.content.length); - buffer.content = ''; - } - } else { - buffer.output = data; - return; + data = hex2ua(data?.data?.output); + if (zsentry === null) { + onOutput(ua2str(data)); + } else { + try { + zsentry.consume(data); + } catch (e) { + console.error(e); } } - term.write(data); return; } if (data?.act === 'WARN') { message.warn(data.msg ? translate(data.msg) : i18n.t('COMMON.UNKNOWN_ERROR')); + return; + } + if (data?.act === 'QUIT') { + message.warn(data.msg ? translate(data.msg) : i18n.t('COMMON.UNKNOWN_ERROR')); + ws.close(); + return; } } } - ws.onclose = (e) => { - if (conn) { - conn = false; - term.write(`\n${i18n.t('COMMON.DISCONNECTED')}\n`); - secret = CryptoJS.enc.Hex.parse(genRandHex(32)); - } + } + function onOutput(data) { + if (buffer.output.length > 0) { + data = buffer.output + data; + buffer.output = ''; } - ws.onerror = (e) => { - console.error(e); - if (conn) { - conn = false; - term.write(`\n${i18n.t('COMMON.DISCONNECTED')}\n`); - secret = CryptoJS.enc.Hex.parse(genRandHex(32)); + if (buffer.content.length > 0) { + if (data.length >= buffer.content.length) { + if (data.startsWith(buffer.content)) { + data = data.substring(buffer.content.length); + buffer.content = ''; + } } else { - term.write(`\n${i18n.t('COMMON.CONNECTION_FAILED')}\n`); + buffer.output = data; + return } } - return termEv; + term.write(data); } + function onWindowsInput(buffer) { let cmd = ''; let index = 0; @@ -144,13 +213,6 @@ function TerminalModal(props) { let history = []; let tempCmd = ''; let tempCursor = 0; - function clearTerm() { - let before = cmd.substring(0, cursor); - let after = cmd.substring(cursor); - term.write('\b'.repeat(wcwidth(before))); - term.write(' '.repeat(wcwidth(cmd))); - term.write('\b'.repeat(wcwidth(cmd))); - } return function (e) { if (!conn) { if (e === '\r' || e === '\n' || e === ' ') { @@ -167,7 +229,7 @@ function TerminalModal(props) { tempCursor = cursor; } index--; - clearTerm.call(this); + clearTerm(); cmd = history[index]; cursor = cmd.length; term.write(cmd); @@ -176,12 +238,12 @@ function TerminalModal(props) { case '\x1B\x5B\x42': // down arrow. if (index + 1 < history.length) { index++; - clearTerm.call(this); + clearTerm(); cmd = history[index]; cursor = cmd.length; term.write(cmd); } else if (index + 1 <= history.length) { - clearTerm.call(this); + clearTerm(); index++; cmd = tempCmd; cursor = tempCursor; @@ -199,14 +261,14 @@ function TerminalModal(props) { break; case '\x1B\x5B\x44': // left arrow. if (cursor > 0) { - term.write('\x1B\x5B\x44'.repeat(wcwidth(cmd[cursor-1]))); + term.write('\x1B\x5B\x44'.repeat(wcwidth(cmd[cursor - 1]))); cursor--; } break; case '\r': case '\n': if (cmd === 'clear' || cmd === 'cls') { - clearTerm.call(this); + clearTerm(); term.clear(); } else { term.write('\n'); @@ -228,7 +290,7 @@ function TerminalModal(props) { cursor--; let charWidth = wcwidth(cmd[cursor]); let before = cmd.substring(0, cursor); - let after = cmd.substring(cursor+1); + let after = cmd.substring(cursor + 1); cmd = before + after; term.write('\b'.repeat(charWidth)); term.write(after + ' '.repeat(charWidth)); @@ -251,6 +313,14 @@ function TerminalModal(props) { } } }; + + function clearTerm() { + let before = cmd.substring(0, cursor); + let after = cmd.substring(cursor); + term.write('\b'.repeat(wcwidth(before))); + term.write(' '.repeat(wcwidth(cmd))); + term.write('\b'.repeat(wcwidth(cmd))); + } } function onUnixOSInput(_) { return function (e) { @@ -264,13 +334,134 @@ function TerminalModal(props) { sendUnixOSInput(e); }; } + function initZmodem() { + const clear = () => { + extKeyRef.current.setFileSelect(false); + zsession._last_header_name = 'ZRINIT'; + zsession.close(); + zsession = null; + }; + zsentry = new Zmodem.Sentry({ + on_retract: () => {}, + on_detect: detection => { + if (zsession !== null) { + clear(); + } + zsession = detection.confirm(); + if (zsession.type === 'send') { + uploadFile(zsession); + } else { + downloadFile(zsession); + } + }, + to_terminal: data => { + onOutput(ua2str(new Uint8Array(data))); + }, + sender: data => { + sendData(new Uint8Array(data), true); + } + }); + + function uploadFile() { + return new Promise((resolve, reject) => { + let uploader = document.getElementById('file-uploader'); + let hasFile = false; + uploader.onchange = e => { + extKeyRef.current.setFileSelect(false); + if (zsession === null) { + e.target.value = null; + message.warn(i18n.t('TERMINAL.ZMODEM_UPLOADER_CALL_TIMEOUT')); + return; + } + let file = e.target.files[0]; + if (file === undefined) { + term.write("\n" + i18n.t('TERMINAL.ZMODEM_UPLOADER_NO_FILE') + "\n"); + clear(); + reject('NO_FILE_SELECTED'); + return; + } + hasFile = true; + e.target.value = null; + term.write("\n" + file.name + "\t" + i18n.t('TERMINAL.ZMODEM_TRANSFER_START') + "\n"); + Zmodem.Browser.send_files(zsession, [file], { + on_offer_response: (file, xfer) => { + if (!xfer) { + term.write(file.name + "\t" + i18n.t('TERMINAL.ZMODEM_TRANSFER_REJECTED') + "\n"); + reject('TRANSFER_REJECTED'); + } + }, + on_file_complete: () => { + term.write(file.name + "\t" + i18n.t('TERMINAL.ZMODEM_TRANSFER_SUCCESS') + "\n"); + resolve(); + } + }).catch(e => { + console.error(e); + term.write(file.name + "\t" + i18n.t('TERMINAL.ZMODEM_TRANSFER_FAILED') + "\n"); + reject(e); + }).finally(() => { + clear(); + }); + }; + term.write("\n" + i18n.t('TERMINAL.ZMODEM_UPLOADER_TIP')); + term.write("\n" + i18n.t('TERMINAL.ZMODEM_UPLOADER_WARNING') + "\n"); + extKeyRef.current.setFileSelect(() => { + uploader.click(); + }); + uploader.click(); + setTimeout(() => { + if (!hasFile) { + term.write("\n" + i18n.t('TERMINAL.ZMODEM_UPLOADER_CALL_TIMEOUT') + "\n"); + clear(); + reject('UPLOADER_CALL_TIMEOUT'); + } + }, 10000); + }); + } + function downloadFile() { + return new Promise((resolve, reject) => { + let resolved = false; + let rejected = false; + zsession.on('offer', xfer => { + let detail = xfer.get_details(); + if (detail.size > 16 * 1024 * 1024) { + xfer.skip(); + term.write("\n" + detail.name + "\t" + i18n.t('TERMINAL.ZMODEM_FILE_TOO_LARGE') + "\n"); + } else { + let filename = detail.name; + let content = []; + xfer.on('input', data => { + content.push(new Uint8Array(data)); + }); + xfer.accept().then(() => { + Zmodem.Browser.save_to_disk(content, filename); + term.write("\n" + detail.name + "\t" + i18n.t('TERMINAL.ZMODEM_TRANSFER_SUCCESS') + "\n"); + resolved = true; + resolve(); + }).catch(e => { + console.error(e); + term.write("\n" + detail.name + "\t" + i18n.t('TERMINAL.ZMODEM_TRANSFER_FAILED') + "\n"); + rejected = true; + reject(); + }); + } + }); + zsession.on('session_end', () => { + zsession = null; + if (!resolved && !rejected) { + reject(); + } + }); + zsession.start(); + }); + } + } function sendWindowsInput(input) { if (conn) { sendData({ act: 'TERMINAL_INPUT', data: { - input: CryptoJS.enc.Hex.stringify(CryptoJS.enc.Utf8.parse(input)) + input: str2hex(input) } }); } @@ -293,14 +484,33 @@ function TerminalModal(props) { sendData({ act: 'TERMINAL_INPUT', data: { - input: CryptoJS.enc.Hex.stringify(CryptoJS.enc.Utf8.parse(input)) + input: str2hex(input) } }); } } - function sendData(data) { + function sendData(data, raw) { if (conn) { - ws.send(encrypt(data, secret)); + let body = []; + if (raw) { + if (data.length > 65536) { + let offset = 0; + while (offset < data.length) { + let chunk = data.slice(offset, offset + 65536); + sendData(chunk, true); + offset += chunk.length; + } + } else { + body = data; + } + } else { + body = encrypt(str2ua(JSON.stringify(data)), secret); + } + let buffer = new Uint8Array(body.length + 8); + buffer.set(new Uint8Array([34, 22, 19, 17, 21, raw ? 0 : 1]), 0); + buffer.set(new Uint8Array([body.length >> 8, body.length & 0xFF]), 6); + buffer.set(body, 8); + ws.send(buffer); } } @@ -316,8 +526,8 @@ function TerminalModal(props) { sendData({ act: 'TERMINAL_RESIZE', data: { - width: cols, - height: rows + cols: cols, + rows: rows } }); } @@ -346,20 +556,20 @@ function TerminalModal(props) { draggable={true} maskClosable={false} modalTitle={i18n.t('TERMINAL.TITLE')} - visible={props.visible} + open={props.open} onCancel={props.onCancel} bodyStyle={{padding: 12}} afterClose={afterClose} destroyOnClose={true} footer={null} - height={200} + height={250} width={900} >
+ ) } @@ -375,8 +590,8 @@ function TerminalModal(props) { class ExtKeyboard extends React.Component { constructor(props) { super(props); - this.visible = props.visible; - if (!this.visible) return; + this.open = props.open; + if (!this.open) return; this.funcKeys = [ {key: '\x1B\x4F\x50', label: 'F1'}, {key: '\x1B\x4F\x51', label: 'F2'}, @@ -417,7 +632,10 @@ class ExtKeyboard extends React.Component { )} ); - this.state = {ctrl: false}; + this.state = { + ctrl: false, + fileSelect: false, + }; } onCtrl() { @@ -430,18 +648,26 @@ class ExtKeyboard extends React.Component { onExtKey(key) { this.props.onExtKey(key, true); } + onFileSelect() { + if (typeof this.state.fileSelect === 'function') { + this.state.fileSelect(); + } + } setCtrl(val) { this.setState({ctrl: val}); } + setFileSelect(cb) { + this.setState({fileSelect: cb}); + } render() { - if (!this.visible) return null; + if (!this.open) return null; return ( <> + ):null + } ); } diff --git a/web/src/components/wrapper.js b/web/src/components/wrapper.js index 78c268d..0b9ea3c 100644 --- a/web/src/components/wrapper.js +++ b/web/src/components/wrapper.js @@ -2,10 +2,15 @@ import React from 'react'; import ProLayout, {PageContainer} from '@ant-design/pro-layout'; import zhCN from 'antd/lib/locale/zh_CN'; import en from 'antd/lib/locale/en_US'; -import {getLang} from "../locale/locale"; -import {ConfigProvider} from "antd"; +import {getLang, getLocale} from "../locale/locale"; +import {Button, ConfigProvider, notification} from "antd"; +import axios from "axios"; import './wrapper.css'; +import version from "../config/version.json"; +import ReactMarkdown from "react-markdown"; +import i18n from "i18next"; +promptUpdate(); function wrapper(props) { return ( ); } + function Title() { return (
) } +function promptUpdate() { + let latest = ''; + axios('https://1248.ink/spark/update', { + method: 'POST', + data: version + }).then(res => { + const data = res.data; + const locale = getLocale(); + latest = data?.latest; + + // if is the latest version, don't show update notification + if (!checkVersion(version.version, latest)) return; + + let localCache = getLocalCache(); + if (!shouldPrompt(localCache, latest)) return; + if (!data.versions[latest] || !data.versions[latest].message) return; + + let message = data.versions[latest].message[locale]; + if (!message.content) return; + + notification.open({ + key: 'update', + message: message.title ? {message.title} : undefined, + description: , + onClose: dismissUpdate, + duration: 0 + }); + }).catch(e => { + console.error(e); + }); + + function getLocalCache() { + let localCache = {}; + let localRawCache = localStorage.getItem('updateCache'); + if (localRawCache) { + try { + localCache = JSON.parse(localRawCache); + } catch (e) { + localCache = {}; + } + } + localCache = Object.assign({ + lastCheck: 0, + latestVersion: '0.0.0', + hasDismissed: false + }, localCache); + return localCache; + } + function checkVersion(current, latest) { + let latestVersion = parseInt(String(latest).replaceAll('.', '')); + let currentVersion = parseInt(String(current).replaceAll('.', '')); + return currentVersion < latestVersion; + } + function shouldPrompt(cache, latest) { + let should = true; + let now = Math.floor(Date.now() / 1000); + if (!checkVersion(cache.latestVersion, latest)) { + if (now - cache?.lastCheck < 7 * 86400) { + should = !cache.hasDismissed; + } + } + return should; + } + function dismissUpdate() { + notification.close('update'); + let now = Math.floor(Date.now() / 1000); + localStorage.setItem('updateCache', JSON.stringify({ + lastCheck: now, + latestVersion: latest, + dismissUpdate: true + })); + } + function UpdateNotice(props) { + return ( + <> + + {props.content} + +
+ + +
+ + ); + } +} + + export default wrapper; \ No newline at end of file diff --git a/web/src/config/version.json b/web/src/config/version.json new file mode 100644 index 0000000..07e45ab --- /dev/null +++ b/web/src/config/version.json @@ -0,0 +1,4 @@ +{ + "version": "$VERSION", + "commit": "$COMMIT" +} \ No newline at end of file diff --git a/web/src/locale/en.json b/web/src/locale/en.json index a47e867..2e3b8ab 100644 --- a/web/src/locale/en.json +++ b/web/src/locale/en.json @@ -11,6 +11,9 @@ "COMMON.DISCONNECTED": "Session disconnected", "COMMON.CONNECTION_FAILED": "Connection failed", + "COMMON.UPDATE_DETAILS": "View Details", + "COMMON.UPDATE_DISMISS": "Dismiss", + "COMMON.HOURS": "h", "COMMON.MINUTES": "m", "COMMON.COLON": ": ", @@ -51,7 +54,7 @@ "EXPLORER.TITLE": "File Explorer", "EXPLORER.FILE_NAME": "Name", "EXPLORER.FILE_SIZE": "Size", - "EXPLORER.MODIFY_TIME": "Modify Time", + "EXPLORER.DATE_MODIFIED": "Date Modified", "EXPLORER.FILE": "file", "EXPLORER.FOLDER": "folder", "EXPLORER.RELOAD": "Reload", @@ -111,6 +114,16 @@ "TERMINAL.SESSION_CLOSED": "Terminal session closed", "TERMINAL.SPECIAL_KEYS": "Special Keys", "TERMINAL.FUNCTION_KEYS": "Function Keys", + "TERMINAL.ZMODEM_FILE_TOO_LARGE": "File exceeds the size limit (16MB)", + "TERMINAL.ZMODEM_TRANSFER_START": "File transfer started, please wait...", + "TERMINAL.ZMODEM_TRANSFER_FAILED": "File transfer failed", + "TERMINAL.ZMODEM_TRANSFER_SUCCESS": "File is transferred successfully", + "TERMINAL.ZMODEM_TRANSFER_REJECTED": "Transfer request has been rejected", + "TERMINAL.ZMODEM_UPLOADER_NO_FILE": "No file selected", + "TERMINAL.ZMODEM_UPLOADER_CALL_FAILED": "Failed to pull up file uploader", + "TERMINAL.ZMODEM_UPLOADER_CALL_TIMEOUT": "File selection timeout, please try again", + "TERMINAL.ZMODEM_UPLOADER_TIP": "File selector will open, if not, please click 'Select File' button", + "TERMINAL.ZMODEM_UPLOADER_WARNING": "If no file selected, please wait for 10 seconds to make session timeout", "DESKTOP.TITLE": "Desktop", "DESKTOP.CREATE_SESSION_FAILED": "Failed to create desktop session", diff --git a/web/src/locale/locale.js b/web/src/locale/locale.js index 25ec8b1..9e0329f 100644 --- a/web/src/locale/locale.js +++ b/web/src/locale/locale.js @@ -6,6 +6,7 @@ const locales = { 'zh-CN': 'zh-CN', }; const lang = navigator.language && navigator.language.length ? navigator.language : 'en'; +const locale = locales[lang] || 'en'; let resources = {}; for (const locale in locales) { @@ -24,6 +25,9 @@ i18n.init({ function getLang() { return lang; } +function getLocale() { + return locale; +} -export { getLang }; +export { getLang, getLocale }; export default i18n; \ No newline at end of file diff --git a/web/src/locale/zh-CN.json b/web/src/locale/zh-CN.json index 4d6c644..6e9c82e 100644 --- a/web/src/locale/zh-CN.json +++ b/web/src/locale/zh-CN.json @@ -11,6 +11,9 @@ "COMMON.DISCONNECTED": "连接已断开", "COMMON.CONNECTION_FAILED": "连接失败", + "COMMON.UPDATE_DETAILS": "详情", + "COMMON.UPDATE_DISMISS": "忽略", + "COMMON.HOURS": "小时", "COMMON.MINUTES": "分钟", "COMMON.COLON": ":", @@ -51,7 +54,7 @@ "EXPLORER.TITLE": "文件管理器", "EXPLORER.FILE_NAME": "文件名", "EXPLORER.FILE_SIZE": "大小", - "EXPLORER.MODIFY_TIME": "修改时间", + "EXPLORER.DATE_MODIFIED": "修改时间", "EXPLORER.FILE": "文件", "EXPLORER.FOLDER": "文件夹", "EXPLORER.RELOAD": "刷新", @@ -111,6 +114,16 @@ "TERMINAL.SESSION_CLOSED": "终端会话已关闭", "TERMINAL.SPECIAL_KEYS": "特殊键", "TERMINAL.FUNCTION_KEYS": "功能键", + "TERMINAL.ZMODEM_FILE_TOO_LARGE": "文件大小超出限制(16MB)", + "TERMINAL.ZMODEM_TRANSFER_START": "文件传输已开始,请稍等...", + "TERMINAL.ZMODEM_TRANSFER_FAILED": "文件传输失败", + "TERMINAL.ZMODEM_TRANSFER_SUCCESS": "文件传输完成", + "TERMINAL.ZMODEM_TRANSFER_REJECTED": "传输请求已被拒绝", + "TERMINAL.ZMODEM_UPLOADER_NO_FILE": "未选择文件", + "TERMINAL.ZMODEM_UPLOADER_CALL_FAILED": "文件上传组件调用失败", + "TERMINAL.ZMODEM_UPLOADER_CALL_TIMEOUT": "文件选择超时,请重试", + "TERMINAL.ZMODEM_UPLOADER_TIP": "文件选择器将会打开,如果没有,请手动点击 '选择文件' 按钮", + "TERMINAL.ZMODEM_UPLOADER_WARNING": "如果未选择文件,请等待10秒直至会话超时", "DESKTOP.TITLE": "桌面", "DESKTOP.CREATE_SESSION_FAILED": "桌面会话创建失败", diff --git a/web/src/pages/overview.js b/web/src/pages/overview.js index 52909f8..7c11f38 100644 --- a/web/src/pages/overview.js +++ b/web/src/pages/overview.js @@ -171,7 +171,7 @@ function overview(props) { const tableRef = useRef(); useEffect(() => { - // Auto update is only available when all modal are closed. + // auto update is only available when all modal are closed. if (!runner && !desktop && !procMgr && !explorer && !generate && !terminal) { let id = setInterval(getData, 3000); return () => { @@ -405,12 +405,12 @@ function overview(props) { /> @@ -420,12 +420,12 @@ function overview(props) { onCancel={setRunner.bind(null, false)} /> diff --git a/web/src/utils/utils.js b/web/src/utils/utils.js index 232bf7d..e0918ff 100644 --- a/web/src/utils/utils.js +++ b/web/src/utils/utils.js @@ -2,7 +2,6 @@ import axios from "axios"; import Qs from "qs"; import i18n, {getLang} from "../locale/locale"; import {message} from "antd"; -import CryptoJS from "crypto-js"; let orderCompare; try { @@ -119,7 +118,7 @@ function catchBlobReq(err) { } } -function hex2buf(hex) { +function hex2ua(hex) { if (typeof hex !== 'string') { return new Uint8Array([]); } @@ -130,86 +129,43 @@ function hex2buf(hex) { return new Uint8Array(list.map(byte => parseInt(byte, 16))); } -function ab2str(buffer) { - const array = new Uint8Array(buffer); - let out, i, len, c; - let char2, char3; - - out = ""; - len = array.length; - i = 0; - while (i < len) { - c = array[i++]; - switch (c >> 4) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - out += String.fromCharCode(c); - break; - case 12: - case 13: - char2 = array[i++]; - out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F)); - break; - case 14: - char2 = array[i++]; - char3 = array[i++]; - out += String.fromCharCode(((c & 0x0F) << 12) | - ((char2 & 0x3F) << 6) | - ((char3 & 0x3F) << 0)); - break; - } - } - return out; -} - -function ws2ua(wordArray) { - const l = wordArray.sigBytes; - const words = wordArray.words; - const result = new Uint8Array(l); - let i = 0, j = 0; - while (true) { - if (i === l) - break; - const w = words[j++]; - result[i++] = (w & 0xff000000) >>> 24; - if (i === l) - break; - result[i++] = (w & 0x00ff0000) >>> 16; - if (i === l) - break; - result[i++] = (w & 0x0000ff00) >>> 8; - if (i === l) - break; - result[i++] = (w & 0x000000ff); - } - return result; +function ua2hex(buf) { + let hexArr = Array.prototype.map.call(buf, bit => { + return ('00' + bit.toString(16)).slice(-2); + }); + return hexArr.join(''); +} + +function str2ua(str) { + return new TextEncoder().encode(str); +} + +function ua2str(buf) { + return new TextDecoder().decode(buf); +} + +function hex2str(hex) { + return new TextDecoder().decode(hex2ua(hex)); +} + +function str2hex(str) { + return ua2hex(new TextEncoder().encode(str)); } function encrypt(data, secret) { - let json = JSON.stringify(data); - json = CryptoJS.enc.Utf8.parse(json); - let encrypted = CryptoJS.AES.encrypt(json, secret, { - mode: CryptoJS.mode.CTR, - iv: secret, - padding: CryptoJS.pad.NoPadding - }); - return ws2ua(encrypted.ciphertext); + let buf = data; + for (let i = 0; i < buf.length; i++) { + buf[i] ^= secret[i % secret.length]; + } + return buf; } function decrypt(data, secret) { - data = CryptoJS.lib.WordArray.create(data); - let decrypted = CryptoJS.AES.encrypt(data, secret, { - mode: CryptoJS.mode.CTR, - iv: secret, - padding: CryptoJS.pad.NoPadding - }); - return ab2str(ws2ua(decrypted.ciphertext).buffer); + data = new Uint8Array(data); + for (let i = 0; i < data.length; i++) { + data[i] ^= secret[i % secret.length]; + } + return ua2str(data); } -export {post, request, waitTime, formatSize, tsToTime, getBaseURL, genRandHex, translate, preventClose, catchBlobReq, hex2buf, ab2str, ws2ua, encrypt, decrypt, orderCompare}; \ No newline at end of file +export {post, request, waitTime, formatSize, tsToTime, getBaseURL, genRandHex, translate, preventClose, catchBlobReq, hex2ua, ua2hex, str2ua, ua2str, hex2str, str2hex, encrypt, decrypt, orderCompare}; \ No newline at end of file diff --git a/web/src/vendors/zmodem.js/encode.js b/web/src/vendors/zmodem.js/encode.js new file mode 100644 index 0000000..5cb6344 --- /dev/null +++ b/web/src/vendors/zmodem.js/encode.js @@ -0,0 +1,124 @@ +"use strict"; + +var Zmodem = module.exports; + +const HEX_DIGITS = [ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102 ]; + +const HEX_OCTET_VALUE = {}; +for (var hd=0; hd 0xffff) throw( "Number cannot exceed 16 bits: " + number ) + + return [ number >> 8, number & 0xff ]; + }, + + /** + * Return an array with the given number as 4 little-endian bytes. + * + * @param {number} number - The number to encode. + * + * @returns {number[]} The octet values. + */ + pack_u32_le: function pack_u32_le(number) { + //Can’t bit-shift because that runs into JS’s bit-shift problem. + //(See _updcrc32() for an example.) + var high_bytes = number / 65536; //fraction is ok + + //a little-endian 4-byte sequence + return [ + number & 0xff, + (number & 65535) >> 8, + high_bytes & 0xff, + high_bytes >> 8, + ]; + }, + + /** + * The inverse of pack_u16_be() - i.e., take in 2 octet values + * and parse them as an unsigned, 2-byte big-endian number. + * + * @param {number[]} octets - The octet values (2 of them). + * + * @returns {number} The decoded number. + */ + unpack_u16_be: function unpack_u16_be(bytes_arr) { + return (bytes_arr[0] << 8) + bytes_arr[1]; + }, + + /** + * The inverse of pack_u32_le() - i.e., take in a 4-byte sequence + * and parse it as an unsigned, 4-byte little-endian number. + * + * @param {number[]} octets - The octet values (4 of them). + * + * @returns {number} The decoded number. + */ + unpack_u32_le: function unpack_u32_le(octets) { + // … (254 << 24 is -33554432, according to JavaScript) + return octets[0] + (octets[1] << 8) + (octets[2] << 16) + (octets[3] * 16777216); + }, + + /** + * Encode a series of octet values to be the octet values that + * correspond to the ASCII hex characters for each octet. The + * returned array is suitable for use as binary data. + * + * For example: + * + * Original Hex Returned + * 254 fe 102, 101 + * 12 0c 48, 99 + * 129 81 56, 49 + * + * @param {number[]} octets - The original octet values. + * + * @returns {number[]} The octet values that correspond to an ASCII + * representation of the given octets. + */ + octets_to_hex: function octets_to_hex(octets) { + var hex = []; + for (var o=0; o> 4 ], + HEX_DIGITS[ octets[o] & 0x0f ] + ); + } + + return hex; + }, + + /** + * The inverse of octets_to_hex(): takes an array + * of hex octet pairs and returns their octet values. + * + * @param {number[]} hex_octets - The hex octet values. + * + * @returns {number[]} The parsed octet values. + */ + parse_hex_octets: function parse_hex_octets(hex_octets) { + var octets = new Array(hex_octets.length / 2); + + for (var i=0; i> 8) & 255)] + ^ ((255 & crc) << 8) + ^ cp + ); +} + +function __verify(expect, got) { + var err; + + if ( expect.join() !== got.join() ) { + throw new Zmodem.Error("crc", got, expect); + } +} + +//TODO: use external implementation(s) +Zmodem.CRC = { + + //https://www.lammertbies.nl/comm/info/crc-calculation.html + //CRC-CCITT (XModem) + + /** + * Deduce a given set of octet values’ CRC16, as per the CRC16 + * variant that ZMODEM uses (CRC-CCITT/XModem). + * + * @param {Array} octets - The array of octet values. + * Each array member should be an 8-bit unsigned integer (0-255). + * + * @returns {Array} crc - The CRC, expressed as an array of octet values. + */ + crc16: function crc16(octet_nums) { + var crc = octet_nums[0]; + for (var b=1; b>> 0 //bit-shift to get unsigned + ); + }, + + /** + * Verify a given set of octet values’ CRC16. + * An exception is thrown on failure. + * + * @param {Array} bytes_arr - The array of octet values. + * Each array member should be an 8-bit unsigned integer (0-255). + * + * @param {Array} crc - The CRC to check against, expressed as + * an array of octet values. + */ + verify16: function verify16(bytes_arr, got) { + return __verify( this.crc16(bytes_arr), got ); + }, + + /** + * Verify a given set of octet values’ CRC32. + * An exception is thrown on failure. + * + * @param {Array} bytes_arr - The array of octet values. + * Each array member should be an 8-bit unsigned integer (0-255). + * + * @param {Array} crc - The CRC to check against, expressed as + * an array of octet values. + */ + verify32: function verify32(bytes_arr, crc) { + try { + __verify( this.crc32(bytes_arr), crc ); + } + catch(err) { + err.input = bytes_arr.slice(0); + throw err; + } + }, +}; diff --git a/web/src/vendors/zmodem.js/zdle.js b/web/src/vendors/zmodem.js/zdle.js new file mode 100644 index 0000000..989222e --- /dev/null +++ b/web/src/vendors/zmodem.js/zdle.js @@ -0,0 +1,240 @@ +"use strict"; + +var Zmodem = module.exports; + +Object.assign( + Zmodem, + require("./zmlib") +); + +//encode() variables - declare them here so we don’t +//create them in the function. +var encode_cur, encode_todo; + +const ZDLE = Zmodem.ZMLIB.ZDLE; + +/** + * Class that handles ZDLE encoding and decoding. + * Encoding is subject to a given configuration--specifically, whether + * we want to escape all control characters. Decoding is static; however + * a given string is encoded we can always decode it. + */ +Zmodem.ZDLE = class ZmodemZDLE { + /** + * Create a ZDLE encoder. + * + * @param {object} [config] - The initial configuration. + * @param {object} config.escape_ctrl_chars - Whether the ZDLE encoder + * should escape control characters. + */ + constructor(config) { + this._config = {}; + if (config) { + this.set_escape_ctrl_chars(!!config.escape_ctrl_chars); + } + } + + /** + * Enable or disable control-character escaping. + * You should probably enable this for sender sessions. + * + * @param {boolean} value - Whether to enable (true) or disable (false). + */ + set_escape_ctrl_chars(value) { + if (typeof value !== "boolean") throw "need boolean!"; + + if (value !== this._config.escape_ctrl_chars) { + this._config.escape_ctrl_chars = value; + this._setup_zdle_table(); + } + } + + /** + * Whether or not control-character escaping is enabled. + * + * @return {boolean} Whether the escaping is on (true) or off (false). + */ + escapes_ctrl_chars() { + return !!this._config.escape_ctrl_chars; + } + + //I don’t know of any Zmodem implementations that use ZESC8 + //(“escape_8th_bit”)?? + + /* + ZMODEM software escapes ZDLE, 020, 0220, 021, 0221, 023, and 0223. If + preceded by 0100 or 0300 (@), 015 and 0215 are also escaped to protect the + Telenet command escape CR-@-CR. + */ + + /** + * Encode an array of octet values and return it. + * This will mutate the given array. + * + * @param {number[]} octets - The octet values to transform. + * Each array member should be an 8-bit unsigned integer (0-255). + * This object is mutated in the function. + * + * @returns {number[]} The passed-in array, transformed. This is the + * same object that is passed in. + */ + encode(octets) { + //NB: Performance matters here! + + if (!this._zdle_table) throw "No ZDLE encode table configured!"; + + var zdle_table = this._zdle_table; + + var last_code = this._lastcode; + + var arrbuf = new ArrayBuffer( 2 * octets.length ); + var arrbuf_uint8 = new Uint8Array(arrbuf); + + var escctl_yn = this._config.escape_ctrl_chars; + + var arrbuf_i = 0; + + for (encode_cur=0; encode_cur=0; o--) { + if (octets[o] === ZDLE) { + octets.splice( o, 2, octets[o+1] - 64 ); + } + } + + return octets; + } + + /** + * Remove, ZDLE-decode, and return bytes from the passed-in array. + * If the requested number of ZDLE-encoded bytes isn’t available, + * then the passed-in array is unmodified (and the return is undefined). + * + * @param {number[]} octets - The octet values to transform. + * Each array member should be an 8-bit unsigned integer (0-255). + * This object is mutated in the function. + * + * @param {number} offset - The number of (undecoded) bytes to skip + * at the beginning of the “octets” array. + * + * @param {number} count - The number of bytes (octet values) to return. + * + * @returns {number[]|undefined} An array with the requested number of + * decoded octet values, or undefined if that number of decoded + * octets isn’t available (given the passed-in offset). + */ + static splice(octets, offset, count) { + var so_far = 0; + + if (!offset) offset = 0; + + for (var i = offset; i> 8, + 0, + flags_num, + ]; + } + + //undefined if nonstop I/O is allowed + get_buffer_size() { + return Zmodem.ENCODELIB.unpack_u16_be( this._bytes4.slice(0, 2) ) || undefined; + } + + //Unimplemented: + // can_decrypt + // can_decompress + + //---------------------------------------------------------------------- + //function names taken from Jacques Mattheij’s implementation, + //as used in syncterm. + + can_full_duplex() { + return !!( this._bytes4[3] & ZRINIT_FLAG.CANFDX ); + } + + can_overlap_io() { + return !!( this._bytes4[3] & ZRINIT_FLAG.CANOVIO ); + } + + can_break() { + return !!( this._bytes4[3] & ZRINIT_FLAG.CANBRK ); + } + + can_fcs_32() { + return !!( this._bytes4[3] & ZRINIT_FLAG.CANFC32 ); + } + + escape_ctrl_chars() { + return !!( this._bytes4[3] & ZRINIT_FLAG.ESCCTL ); + } + + //Is this used? I don’t see it used in lrzsz or syncterm + //Looks like it was a “foreseen” feature that Forsberg + //never implemented. (The need for it went away, maybe?) + escape_8th_bit() { + return !!( this._bytes4[3] & ZRINIT_FLAG.ESC8 ); + } +}; + +//---------------------------------------------------------------------- + +//Since context makes clear what’s going on, we use these +//rather than the T-prefixed constants in the specification. +const ZSINIT_FLAG = { + ESCCTL: 0x40, // Transmitter will escape ctl chars + ESC8: 0x80, // Transmitter will escape 8th bit +}; + +function _get_ZSINIT_flag_num(fl) { + if (!ZSINIT_FLAG[fl]) { + throw("Invalid ZSINIT flag: " + fl); + } + return ZSINIT_FLAG[fl]; +} + +class ZSINIT_HEADER extends Zmodem.Header { + constructor( flags_arr, attn_seq_arr ) { + super(); + var flags_num = 0; + + flags_arr.forEach( function(fl) { + flags_num |= _get_ZSINIT_flag_num(fl); + } ); + + this._bytes4 = [ 0, 0, 0, flags_num ]; + + if (attn_seq_arr) { + if (attn_seq_arr.length > 31) { + throw("Attn sequence must be <= 31 bytes"); + } + if (attn_seq_arr.some( function(num) { return num > 255 } )) { + throw("Attn sequence (" + attn_seq_arr + ") must be <256"); + } + this._data = attn_seq_arr.concat([0]); + } + } + + escape_ctrl_chars() { + return !!( this._bytes4[3] & ZSINIT_FLAG.ESCCTL ); + } + + //Is this used? I don’t see it used in lrzsz or syncterm + escape_8th_bit() { + return !!( this._bytes4[3] & ZSINIT_FLAG.ESC8 ); + } +} + +//Thus far it doesn’t seem we really need this header except to respond +//to ZSINIT, which doesn’t require a payload. +class ZACK_HEADER extends Zmodem.Header { + constructor(payload4) { + super(); + + if (payload4) { + this._bytes4 = payload4.slice(); + } + } +} +ZACK_HEADER.prototype._hex_header_ending = HEX_HEADER_CRLF; + +//---------------------------------------------------------------------- + +const ZFILE_VALUES = { + + //ZF3 (i.e., first byte) + extended: { + sparse: 0x40, //ZXSPARS + }, + + //ZF2 + transport: [ + undefined, + "compress", //ZTLZW + "encrypt", //ZTCRYPT + "rle", //ZTRLE + ], + + //ZF1 + management: [ + undefined, + "newer_or_longer", //ZF1_ZMNEWL + "crc", //ZF1_ZMCRC + "append", //ZF1_ZMAPND + "clobber", //ZF1_ZMCLOB + "newer", //ZF1_ZMNEW + "mtime_or_length", //ZF1_ZMNEW + "protect", //ZF1_ZMPROT + "rename", //ZF1_ZMPROT + ], + + //ZF0 (i.e., last byte) + conversion: [ + undefined, + "binary", //ZCBIN + "text", //ZCNL + "resume", //ZCRESUM + ], +}; + +const ZFILE_ORDER = ["extended", "transport", "management", "conversion"]; + +const ZMSKNOLOC = 0x80, + MANAGEMENT_MASK = 0x1f, + ZXSPARS = 0x40 +; + +class ZFILE_HEADER extends Zmodem.Header { + + //TODO: allow options on instantiation + get_options() { + var opts = { + sparse: !!(this._bytes4[0] & ZXSPARS), + }; + + var bytes_copy = this._bytes4.slice(0); + + ZFILE_ORDER.forEach( function(key, i) { + if (ZFILE_VALUES[key] instanceof Array) { + if (key === "management") { + opts.skip_if_absent = !!(bytes_copy[i] & ZMSKNOLOC); + bytes_copy[i] &= MANAGEMENT_MASK; + } + + opts[key] = ZFILE_VALUES[key][ bytes_copy[i] ]; + } + else { + for (var extkey in ZFILE_VALUES[key]) { + opts[extkey] = !!(bytes_copy[i] & ZFILE_VALUES[key][extkey]); + if (opts[extkey]) { + bytes_copy[i] ^= ZFILE_VALUES[key][extkey] + } + } + } + + if (!opts[key] && bytes_copy[i]) { + opts[key] = "unknown:" + bytes_copy[i]; + } + } ); + + return opts; + } +} + +//---------------------------------------------------------------------- + +//Empty headers - in addition to ZRQINIT +class ZSKIP_HEADER extends Zmodem.Header {} +//No need for ZNAK +class ZABORT_HEADER extends Zmodem.Header {} +class ZFIN_HEADER extends Zmodem.Header {} +class ZFERR_HEADER extends Zmodem.Header {} + +ZFIN_HEADER.prototype._hex_header_ending = HEX_HEADER_CRLF; + +class ZOffsetHeader extends Zmodem.Header { + constructor(offset) { + super(); + this._bytes4 = Zmodem.ENCODELIB.pack_u32_le(offset); + } + + get_offset() { + return Zmodem.ENCODELIB.unpack_u32_le(this._bytes4); + } +} + +class ZRPOS_HEADER extends ZOffsetHeader {}; +class ZDATA_HEADER extends ZOffsetHeader {}; +class ZEOF_HEADER extends ZOffsetHeader {}; + +//As request, receiver creates. +/* UNIMPLEMENTED FOR NOW +class ZCRC_HEADER extends ZHeader { + constructor(crc_le_bytes) { + super(); + if (crc_le_bytes) { //response, sender creates + this._bytes4 = crc_le_bytes; + } + } +} +*/ + +//No ZCHALLENGE implementation + +//class ZCOMPL_HEADER extends ZHeader {} +//class ZCAN_HEADER extends Zmodem.Header {} + +//As described, this header represents an information disclosure. +//It could be interpreted, I suppose, merely as “this is how much space +//I have FOR YOU.” +//TODO: implement if needed/requested +//class ZFREECNT_HEADER extends ZmodemHeader {} + +//---------------------------------------------------------------------- + +const FRAME_CLASS_TYPES = [ + [ ZRQINIT_HEADER, "ZRQINIT" ], + [ ZRINIT_HEADER, "ZRINIT" ], + [ ZSINIT_HEADER, "ZSINIT" ], + [ ZACK_HEADER, "ZACK" ], + [ ZFILE_HEADER, "ZFILE" ], + [ ZSKIP_HEADER, "ZSKIP" ], + undefined, // [ ZNAK_HEADER, "ZNAK" ], + [ ZABORT_HEADER, "ZABORT" ], + [ ZFIN_HEADER, "ZFIN" ], + [ ZRPOS_HEADER, "ZRPOS" ], + [ ZDATA_HEADER, "ZDATA" ], + [ ZEOF_HEADER, "ZEOF" ], + [ ZFERR_HEADER, "ZFERR" ], //see note + undefined, //[ ZCRC_HEADER, "ZCRC" ], + undefined, //[ ZCHALLENGE_HEADER, "ZCHALLENGE" ], + undefined, //[ ZCOMPL_HEADER, "ZCOMPL" ], + undefined, //[ ZCAN_HEADER, "ZCAN" ], + undefined, //[ ZFREECNT_HEADER, "ZFREECNT" ], + undefined, //[ ZCOMMAND_HEADER, "ZCOMMAND" ], + undefined, //[ ZSTDERR_HEADER, "ZSTDERR" ], +]; + +/* +ZFERR is described as “error in reading or writing file”. It’s really +not a good idea from a security angle for the endpoint to expose this +information. We should parse this and handle it as ZABORT but never send it. + +Likewise with ZFREECNT: the sender shouldn’t ask how much space is left +on the other box; rather, the receiver should decide what to do with the +file size as the sender reports it. +*/ + +var FRAME_NAME_CREATOR = {}; + +for (var fc=0; fc 11) { + hdr_err = "Invalid hex header - no LF detected within 12 bytes!"; + } + + //incomplete header + return; + } + else { + hex_bytes = bytes_arr.splice( 0, lf_pos ); + + //Trim off the LF + bytes_arr.shift(); + + if ( hex_bytes.length === 19 ) { + + //NB: The spec says CR but seems to treat high-bit variants + //of control characters the same as the regulars; should we + //also allow 0x8d? + var preceding = hex_bytes.pop(); + if ( preceding !== 0x0d && preceding !== 0x8d ) { + hdr_err = "Invalid hex header: (CR/)LF doesn’t have CR!"; + } + } + else if ( hex_bytes.length !== 18 ) { + hdr_err = "Invalid hex header: invalid number of bytes before LF!"; + } + } + + if (hdr_err) { + hdr_err += " (" + hex_bytes.length + " bytes: " + hex_bytes.join() + ")"; + throw hdr_err; + } + + hex_bytes.splice(0, 4); + + //Should be 7 bytes ultimately: + // 1 for typenum + // 4 for header data + // 2 for CRC + var octets = Zmodem.ENCODELIB.parse_hex_octets(hex_bytes); + + return _parse_non_zdle_binary16(octets); +} + +Zmodem.Header.parse_hex = _parse_hex; diff --git a/web/src/vendors/zmodem.js/zmlib.js b/web/src/vendors/zmodem.js/zmlib.js new file mode 100644 index 0000000..f86070d --- /dev/null +++ b/web/src/vendors/zmodem.js/zmlib.js @@ -0,0 +1,102 @@ +"use strict"; + +var Zmodem = module.exports; + +const + ZDLE = 0x18, + XON = 0x11, + XOFF = 0x13, + XON_HIGH = 0x80 | XON, + XOFF_HIGH = 0x80 | XOFF, + CAN = 0x18 //NB: same character as ZDLE +; + +/** + * Tools and constants that are useful for ZMODEM. + * + * @exports ZMLIB + */ +Zmodem.ZMLIB = { + + /** + * @property {number} The ZDLE constant, which ZMODEM uses for escaping + */ + ZDLE: ZDLE, + + /** + * @property {number} XON - ASCII XON + */ + XON: XON, + + /** + * @property {number} XOFF - ASCII XOFF + */ + XOFF: XOFF, + + /** + * @property {number[]} ABORT_SEQUENCE - ZMODEM’s abort sequence + */ + ABORT_SEQUENCE: [ CAN, CAN, CAN, CAN, CAN ], + + /** + * Remove octet values from the given array that ZMODEM always ignores. + * This will mutate the given array. + * + * @param {number[]} octets - The octet values to transform. + * Each array member should be an 8-bit unsigned integer (0-255). + * This object is mutated in the function. + * + * @returns {number[]} The passed-in array. This is the same object that is + * passed in. + */ + strip_ignored_bytes: function strip_ignored_bytes(octets) { + for (var o=octets.length-1; o>=0; o--) { + switch (octets[o]) { + case XON: + case XON_HIGH: + case XOFF: + case XOFF_HIGH: + octets.splice(o, 1); + continue; + } + } + + return octets; + }, + + /** + * Like Array.prototype.indexOf, but searches for a subarray + * rather than just a particular value. + * + * @param {Array} haystack - The array to search, i.e., the bigger. + * + * @param {Array} needle - The array whose values to find, + * i.e., the smaller. + * + * @returns {number} The position in “haystack” where “needle” + * first appears—or, -1 if “needle” doesn’t appear anywhere + * in “haystack”. + */ + find_subarray: function find_subarray(haystack, needle) { + var h=0, n; + + var start = Date.now(); + + HAYSTACK: + while (h !== -1) { + h = haystack.indexOf( needle[0], h ); + if (h === -1) break HAYSTACK; + + for (n=1; n=0; f--) { + var fobj = files[f]; + total_size += fobj.size; + batch[f] = { + obj: fobj, + name: fobj.name, + size: fobj.size, + mtime: new Date(fobj.lastModified), + files_remaining: files.length - f, + bytes_remaining: total_size, + }; + } + + var file_idx = 0; + function promise_callback() { + var cur_b = batch[file_idx]; + + if (!cur_b) { + return Promise.resolve(); //batch done! + } + + file_idx++; + + return session.send_offer(cur_b).then( function after_send_offer(xfer) { + if (options.on_offer_response) { + options.on_offer_response(cur_b.obj, xfer); + } + + if (xfer === undefined) { + return promise_callback(); //skipped + } + + return new Promise( function(res) { + var reader = new FileReader(); + + //This really shouldn’t happen … so let’s + //blow up if it does. + reader.onerror = function reader_onerror(e) { + console.error("file read error", e); + throw("File read error: " + e); + }; + + var piece; + reader.onprogress = function reader_onprogress(e) { + + //Some browsers (e.g., Chrome) give partial returns, + //while others (e.g., Firefox) don’t. + if (e.target.result) { + piece = new Uint8Array(e.target.result, xfer.get_offset()) + + _check_aborted(session); + + xfer.send(piece); + + if (options.on_progress) { + options.on_progress(cur_b.obj, xfer, piece); + } + } + }; + + reader.onload = function reader_onload(e) { + piece = new Uint8Array(e.target.result, xfer, piece) + + _check_aborted(session); + + xfer.end(piece).then( function() { + if (options.on_progress && piece.length) { + options.on_progress(cur_b.obj, xfer, piece); + } + + if (options.on_file_complete) { + options.on_file_complete(cur_b.obj, xfer); + } + + //Resolve the current file-send promise with + //another promise. That promise resolves immediately + //if we’re done, or with another file-send promise + //if there’s more to send. + res( promise_callback() ); + } ); + }; + + reader.readAsArrayBuffer(cur_b.obj); + } ); + } ); + } + + return promise_callback(); + }, + + /** + * Prompt a user to save the given packets as a file by injecting an + * `` element (with `display: none` styling) into the page and + * calling the element’s `click()` + * method. The element is removed immediately after. + * + * @param {Array} packets - Same as the first argument to [Blob’s constructor](https://developer.mozilla.org/en-US/docs/Web/API/Blob). + * @param {string} name - The name to give the file. + */ + save_to_disk: function save_to_disk(packets, name) { + var blob = new Blob(packets); + var url = URL.createObjectURL(blob); + + var el = document.createElement("a"); + el.style.display = "none"; + el.href = url; + el.download = name; + + //It seems like a security problem that this actually works; + //I’d think there would need to be some confirmation before + //a browser could save arbitrarily many bytes onto the disk. + //But, hey. + el.click(); + setTimeout(() => URL.revokeObjectURL(url), 10000); + }, +}; diff --git a/web/src/vendors/zmodem.js/zsentry.js b/web/src/vendors/zmodem.js/zsentry.js new file mode 100644 index 0000000..470769a --- /dev/null +++ b/web/src/vendors/zmodem.js/zsentry.js @@ -0,0 +1,394 @@ +"use strict"; + +var Zmodem = module.exports; + +Object.assign( + Zmodem, + require("./zmlib"), + require("./zsession") +); + +const + MIN_ZM_HEX_START_LENGTH = 20, + MAX_ZM_HEX_START_LENGTH = 21, + + // **, ZDLE, 'B0' + //ZRQINIT’s next byte will be '0'; ZRINIT’s will be '1'. + COMMON_ZM_HEX_START = [ 42, 42, 24, 66, 48 ], + + SENTRY_CONSTRUCTOR_REQUIRED_ARGS = [ + "to_terminal", + "on_detect", + "on_retract", + "sender", + ], + + ASTERISK = 42 +; + +/** + * An instance of this object is passed to the Sentry’s on_detect + * callback each time the Sentry object sees what looks like the + * start of a ZMODEM session. + * + * Note that it is possible for a detection to be “retracted” + * if the Sentry consumes bytes afterward that are not ZMODEM. + * When this happens, the Sentry’s `retract` event will fire, + * after which the Detection object is no longer usable. + */ +class Detection { + + /** + * Not called directly. + */ + constructor(session_type, accepter, denier, checker) { + + //confirm() - user confirms that ZMODEM is desired + this._confirmer = accepter; + + //deny() - user declines ZMODEM; send abort sequence + // + //TODO: It might be ideal to forgo the session “peaceably”, + //i.e., such that the peer doesn’t end in error. That’s + //possible if we’re the sender, we accept the session, + //then we just send a close(), but it doesn’t seem to be + //possible for a receiver. Thus, let’s just leave it so + //it’s at least consistent (and simpler, too). + this._denier = denier; + + this._is_valid = checker; + + this._session_type = session_type; + } + + /** + * Confirm that the detected ZMODEM sequence indicates the + * start of a ZMODEM session. + * + * @return {Session} The ZMODEM Session object (i.e., either a + * Send or Receive instance). + */ + confirm() { + return this._confirmer.apply(this, arguments); + } + + /** + * Tell the Sentry that the detected bytes sequence is + * **NOT** intended to be the start of a ZMODEM session. + */ + deny() { + return this._denier.apply(this, arguments); + } + + /** + * Tells whether the Detection is still valid; i.e., whether + * the Sentry has `consume()`d bytes that invalidate the + * Detection. + * + * @returns {boolean} Whether the Detection is valid. + */ + is_valid() { + return this._is_valid.apply(this, arguments); + } + + /** + * Gives the session’s role. + * + * @returns {string} One of: + * - `receive` + * - `send` + */ + get_session_role() { return this._session_type } +} + +/** + * Class that parses an input stream for the beginning of a + * ZMODEM session. We look for the tell-tale signs + * of a ZMODEM transfer and allow the client to determine whether + * it’s really ZMODEM or not. + * + * This is the “mother” class for zmodem.js; + * all other class instances are created, directly or indirectly, + * by an instance of this class. + * + * This logic is not unlikely to need tweaking, and it can never + * be fully bulletproof; if it could be bulletproof it would be + * simpler since there wouldn’t need to be the .confirm()/.deny() + * step. + * + * One thing you could do to make things a bit simpler *is* just + * to make that assumption for your users--i.e., to .confirm() + * Detection objects automatically. That’ll be one less step + * for the user, but an unaccustomed user might find that a bit + * confusing. It’s also then possible to have a “false positive”: + * a text stream that contains a ZMODEM initialization string but + * isn’t, in fact, meant to start a ZMODEM session. + * + * Workflow: + * - parse all input with .consume(). As long as nothing looks + * like ZMODEM, all the traffic will go to to_terminal(). + * + * - when a “tell-tale” sequence of bytes arrives, we create a + * Detection object and pass it to the “on_detect” handler. + * + * - Either .confirm() or .deny() with the Detection object. + * This is the user’s chance to say, “yeah, I know those + * bytes look like ZMODEM, but they’re not. So back off!” + * + * If you .confirm(), the Session object is returned, and + * further input that goes to the Sentry’s .consume() will + * go to the (now-active) Session object. + * + * - Sometimes additional traffic arrives that makes it apparent + * that no ZMODEM session is intended to start; in this case, + * the Sentry marks the Detection as “stale” and calls the + * `on_retract` handler. Any attempt from here to .confirm() + * on the Detection object will prompt an exception. + * + * (This “retraction” behavior will only happen prior to + * .confirm() or .deny() being called on the Detection object. + * Beyond that point, either the Session has to deal with the + * “garbage”, or it’s back to the terminal anyway. + * + * - Once the Session object is done, the Sentry will again send + * all traffic to to_terminal(). + */ +Zmodem.Sentry = class ZmodemSentry { + + /** + * Invoked directly. Creates a new Sentry that inspects all + * traffic before it goes to the terminal. + * + * @param {Object} options - The Sentry parameters + * + * @param {Function} options.to_terminal - Handler that sends + * traffic to the terminal object. Receives an iterable object + * (e.g., an Array) that contains octet numbers. + * + * @param {Function} options.on_detect - Handler for new + * detection events. Receives a new Detection object. + * + * @param {Function} options.on_retract - Handler for retraction + * events. Receives no input. + * + * @param {Function} options.sender - Handler that sends traffic to + * the peer. If, for example, your application uses WebSocket to talk + * to the peer, use this to send data to the WebSocket instance. + */ + constructor(options) { + if (!options) throw "Need options!"; + + var sentry = this; + SENTRY_CONSTRUCTOR_REQUIRED_ARGS.forEach( function(arg) { + if (!options[arg]) { + throw "Need “" + arg + "”!"; + } + sentry["_" + arg] = options[arg]; + } ); + + this._cache = []; + } + + _after_session_end() { + this._zsession = null; + } + + /** + * “Consumes” a piece of input: + * + * - If there is no active or pending ZMODEM session, the text is + * all output. (This is regardless of whether we’ve got a new + * Detection.) + * + * - If there is no active ZMODEM session and the input **ends** with + * a ZRINIT or ZRQINIT, then a new Detection object is created, + * and it is passed to the “on_detect” function. + * If there was another pending Detection object, it is retracted. + * + * - If there is no active ZMODEM session and the input does NOT end + * with a ZRINIT or ZRQINIT, then any pending Detection object is + * retracted. + * + * - If there is an active ZMODEM session, the input is passed to it. + * Any non-ZMODEM data (i.e., “garbage”) parsed from the input + * is sent to output. + * If the ZMODEM session ends, any post-ZMODEM part of the input + * is sent to output. + * + * @param {number[] | ArrayBuffer} input - Octets to parse as input. + */ + consume(input) { + if (!(input instanceof Array)) { + input = Array.prototype.slice.call( new Uint8Array(input) ); + } + + if (this._zsession) { + var session_before_consume = this._zsession; + + session_before_consume.consume(input); + + if (session_before_consume.has_ended()) { + if (session_before_consume.type === "receive") { + input = session_before_consume.get_trailing_bytes(); + } + else { + input = []; + } + } + else return; + } + + var new_session = this._parse(input); + var to_terminal = input; + + if (new_session) { + let replacement_detect = !!this._parsed_session; + + if (replacement_detect) { + //no terminal output if the new session is of the + //same type as the old + if (this._parsed_session.type === new_session.type) { + to_terminal = []; + } + + this._on_retract(); + } + + this._parsed_session = new_session; + + var sentry = this; + + function checker() { + return sentry._parsed_session === new_session; + } + + //This runs with the Sentry object as the context. + function accepter() { + if (!this.is_valid()) { + throw "Stale ZMODEM session!"; + } + + new_session.on("garbage", sentry._to_terminal); + + new_session.on( + "session_end", + sentry._after_session_end.bind(sentry) + ); + + new_session.set_sender(sentry._sender); + + delete sentry._parsed_session; + + return sentry._zsession = new_session; + }; + + function denier() { + if (!this.is_valid()) return; + }; + + this._on_detect( new Detection( + new_session.type, + accepter, + this._send_abort.bind(this), + checker + ) ); + } + else { + /* + if (this._parsed_session) { + this._session_stale_because = 'Non-ZMODEM output received after ZMODEM initialization.'; + } + */ + + var expired_session = this._parsed_session; + + this._parsed_session = null; + + if (expired_session) { + + //If we got a single “C” after parsing a session, + //that means our peer is trying to downgrade to YMODEM. + //That won’t work, so we just send the ABORT_SEQUENCE + //right away. + if (to_terminal.length === 1 && to_terminal[0] === 67) { + this._send_abort(); + } + + this._on_retract(); + } + } + + this._to_terminal(to_terminal); + } + + /** + * @return {Session|null} The sentry’s current Session object, or + * null if there is none. + */ + get_confirmed_session() { + return this._zsession || null; + } + + _send_abort() { + this._sender( Zmodem.ZMLIB.ABORT_SEQUENCE ); + } + + /** + * Parse an input stream and decide how much of it goes to the + * terminal or to a new Session object. + * + * This will accommodate input strings that are fragmented + * across calls to this function; e.g., if you send the first + * two bytes at the end of one parse() call then send the rest + * at the beginning of the next, parse() will recognize it as + * the beginning of a ZMODEM session. + * + * In order to keep from blocking any actual useful data to the + * terminal in real-time, this will send on the initial + * ZRINIT/ZRQINIT bytes to the terminal. They’re meant to go to the + * terminal anyway, so that should be fine. + * + * @private + * + * @param {Array|Uint8Array} array_like - The input bytes. + * Each member should be a number between 0 and 255 (inclusive). + * + * @return {Array} A two-member list: + * 0) the bytes that should be printed on the terminal + * 1) the created Session object (if any) + */ + _parse(array_like) { + var cache = this._cache; + + cache.push.apply( cache, array_like ); + + while (true) { + let common_hex_at = Zmodem.ZMLIB.find_subarray( cache, COMMON_ZM_HEX_START ); + if (-1 === common_hex_at) break; + + let before_common_hex = cache.splice(0, common_hex_at); + let zsession; + try { + zsession = Zmodem.Session.parse(cache); + } catch(err) { //ignore errors + //console.log(err); + } + + if (!zsession) break; + + //Don’t need to parse the trailing XON. + if ((cache.length === 1) && (cache[0] === Zmodem.ZMLIB.XON)) { + cache.shift(); + } + + //If there are still bytes in the cache, + //then we don’t have a ZMODEM session. This logic depends + //on the sender only sending one initial header. + return cache.length ? null : zsession; + } + + cache.splice( MAX_ZM_HEX_START_LENGTH ); + + return null; + } +} diff --git a/web/src/vendors/zmodem.js/zsession.js b/web/src/vendors/zmodem.js/zsession.js new file mode 100644 index 0000000..71aee7d --- /dev/null +++ b/web/src/vendors/zmodem.js/zsession.js @@ -0,0 +1,1683 @@ +"use strict"; + +var Zmodem = module.exports; + +/** + * This is where the protocol-level logic lives: the interaction of ZMODEM + * headers and subpackets. The logic here is not unlikely to need tweaking + * as little edge cases crop up. + */ + +Zmodem.DEBUG = false; + +Object.assign( + Zmodem, + require("./encode"), + require("./text"), + require("./zdle"), + require("./zmlib"), + require("./zheader"), + require("./zsubpacket"), + require("./zvalidation"), + require("./zerror") +); + +const + //pertinent to this module + KEEPALIVE_INTERVAL = 5000, + + //We ourselves don’t need ESCCTL, so we don’t send it; + //however, we always expect to receive it in ZRINIT. + //See _ensure_receiver_escapes_ctrl_chars() for more details. + ZRINIT_FLAGS = [ + "CANFDX", //full duplex + "CANOVIO", //overlap I/O + + //lsz has a buffer overflow bug that shows itself when: + // + // - 16-bit CRC is used, and + // - lsz receives the abort sequence while sending a file + // + //To avoid this, we just tell lsz to use 32-bit CRC + //even though there is otherwise no reason. This ensures that + //unfixed lsz versions will avoid the buffer overflow. + "CANFC32", + ], + + //We do this because some WebSocket shell servers + //(e.g., xterm.js’s demo server) enable the IEXTEN termios flag, + //which bars 0x0f and 0x16 from reaching the shell process, + //which results in transmission errors. + FORCE_ESCAPE_CTRL_CHARS = true, + + DEFAULT_RECEIVE_INPUT_MODE = "spool_uint8array", + + //pertinent to ZMODEM + MAX_CHUNK_LENGTH = 8192, //1 KiB officially, but lrzsz allows 8192 + BS = 0x8, + OVER_AND_OUT = [ 79, 79 ], + ABORT_SEQUENCE = Zmodem.ZMLIB.ABORT_SEQUENCE +; + +/** + * A base class for objects that have events. + * + * @private + */ +class _Eventer { + + /** + * Not called directly. + */ + constructor() { + this._on_evt = {}; + this._evt_once_index = {}; + } + + _Add_event(evt_name) { + this._on_evt[evt_name] = []; + this._evt_once_index[evt_name] = []; + } + + _get_evt_queue(evt_name) { + if (!this._on_evt[evt_name]) { + throw( "Bad event: " + evt_name ); + } + + return this._on_evt[evt_name]; + } + + /** + * Register a callback for a given event. + * + * @param {string} evt_name - The name of the event. + * + * @param {Function} todo - The function to execute when the event happens. + */ + on(evt_name, todo) { + var queue = this._get_evt_queue(evt_name); + + queue.push(todo); + + return this; + } + + /** + * Unregister a callback for a given event. + * + * @param {string} evt_name - The name of the event. + * + * @param {Function} [todo] - The function to execute when the event + * happens. If not given, the last event registered for the event + * is unregistered. + */ + off(evt_name, todo) { + var queue = this._get_evt_queue(evt_name); + + if (todo) { + var at = queue.indexOf(todo); + if (at === -1) { + throw("“" + todo + "” is not in the “" + evt_name + "” queue."); + } + queue.splice(at, 1); + } + else { + queue.pop(); + } + + return this; + } + + _Happen(evt_name /*, arg0, arg1, .. */) { + var queue = this._get_evt_queue(evt_name); //might as well validate + + //console.info("EVENT", this, arguments); + + var args = Array.apply(null, arguments); + args.shift(); + + var sess = this; + + queue.forEach( function(cb) { cb.apply(sess, args) } ); + + return queue.length; + } +} + +/** + * The Session classes handle the protocol-level logic. + * These shield the user from dealing with headers and subpackets. + * This is a base class with functionality common to both Receive + * and Send subclasses. + * + * @extends _Eventer +*/ +Zmodem.Session = class ZmodemSession extends _Eventer { + + /** + * Parse out a hex header from the given array. + * If there’s a ZRQINIT or ZRINIT at the beginning, + * we’ll return it. If the input isn’t a header, + * for whatever reason, we return undefined. + * + * @param {number[]} octets - The bytes to parse. + * + * @return {Session|undefined} A Session object if the beginning + * of a session was parsable in “octets”; otherwise undefined. + */ + static parse( octets ) { + + //Will need to trap errors. + var hdr; + try { + hdr = Zmodem.Header.parse_hex(octets); + } + catch(e) { //Don’t report since we aren’t in session + + //debug + //console.warn("No hex header: ", e); + + return; + } + + if (!hdr) return; + + switch (hdr.NAME) { + case "ZRQINIT": + //throw if ZCOMMAND + return new Zmodem.Session.Receive(); + case "ZRINIT": + return new Zmodem.Session.Send(hdr); + } + + //console.warn("Invalid first Zmodem header", hdr); + } + + /** + * Sets the sender function that a Session object will use. + * + * @param {Function} sender_func - The function to call. + * It will receive an Array with the relevant octets. + * + * @return {Session} The session object (for chaining). + */ + set_sender(sender_func) { + this._sender = sender_func; + return this; + } + + /** + * Whether the current Session has ended. + * + * @returns {boolean} The ended state. + */ + has_ended() { return this._has_ended() } + + /** + * Consumes an array of octets as ZMODEM session input. + * + * @param {number[]} octets - The input octets. + */ + consume(octets) { + this._before_consume(octets); + + if (this._aborted) throw new Zmodem.Error('already_aborted'); + + if (!octets.length) return; + + this._strip_and_enqueue_input(octets); + + if (!this._check_for_abort_sequence(octets)) { + this._consume_first(); + } + + return; + } + + /** + * Whether the current Session has been `abort()`ed. + * + * @returns {boolean} The aborted state. + */ + aborted() { return !!this._aborted } + + /** + * Not called directly. + */ + constructor() { + super(); + //if (!sender_func) throw "Need sender!"; + + //this._first_header = first_header; + //this._sender = sender_func; + this._config = {}; + + //this._input = new ZInput(); + + this._input_buffer = []; + + //This is mostly for debugging. + this._Add_event("receive"); + this._Add_event("garbage"); + this._Add_event("session_end"); + } + + /** + * Returns the Session object’s role. + * + * @returns {string} One of: + * - `receive` + * - `send` + */ + get_role() { return this.type } + + _trim_leading_garbage_until_header() { + var garbage = Zmodem.Header.trim_leading_garbage(this._input_buffer); + + if (garbage.length) { + if (this._Happen("garbage", garbage) === 0) { + console.debug( + "Garbage: ", + String.fromCharCode.apply(String, garbage), + garbage + ); + } + } + } + + _parse_and_consume_header() { + this._trim_leading_garbage_until_header(); + + var new_header_and_crc = Zmodem.Header.parse(this._input_buffer); + if (!new_header_and_crc) return; + + if (Zmodem.DEBUG) { + this._log_header( "RECEIVED HEADER", new_header_and_crc[0] ); + } + + this._consume_header(new_header_and_crc[0]); + + this._last_header_name = new_header_and_crc[0].NAME; + this._last_header_crc = new_header_and_crc[1]; + + return new_header_and_crc[0]; + } + + _log_header(label, header) { + console.debug(this.type, label, header.NAME, header._bytes4.join()); + } + + _consume_header(new_header) { + this._on_receive(new_header); + + var handler = this._next_header_handler && this._next_header_handler[ new_header.NAME ]; + if (!handler) { + console.error("Unhandled header!", new_header, this._next_header_handler); + throw new Zmodem.Error( "Unhandled header: " + new_header.NAME ); + } + + this._next_header_handler = null; + + handler.call(this, new_header); + } + + //TODO: strip out the abort sequence + _check_for_abort_sequence() { + var abort_at = Zmodem.ZMLIB.find_subarray( this._input_buffer, ABORT_SEQUENCE ); + + if (abort_at !== -1) { + + //TODO: expose this to caller + this._input_buffer.splice( 0, abort_at + ABORT_SEQUENCE.length ); + + this._aborted = true; + + //TODO compare response here to lrzsz. + this._on_session_end(); + + //We shouldn’t ever expect to receive an abort. Even if we + //have sent an abort ourselves, the Sentry should have stopped + //directing input to this Session object. + //if (this._expect_abort) { + // return true; + //} + + throw new Zmodem.Error("peer_aborted"); + } + } + + _send_header(name /*, args */) { + if (!this._sender) throw "Need sender!"; + + var args = Array.apply( null, arguments ); + + var bytes_hdr = this._create_header_bytes(args); + + if (Zmodem.DEBUG) { + this._log_header( "SENDING HEADER", bytes_hdr[1] ); + } + + this._sender(bytes_hdr[0]); + + this._last_sent_header = bytes_hdr[1]; + } + + _create_header_bytes(name_and_args) { + + var hdr = Zmodem.Header.build.apply( Zmodem.Header, name_and_args ); + + var formatter = this._get_header_formatter(name_and_args[0]); + + return [ + hdr[formatter](this._zencoder), + hdr + ]; + } + + _strip_and_enqueue_input(input) { + Zmodem.ZMLIB.strip_ignored_bytes(input); + + //It’s possible that “input” is empty at this point. + //It doesn’t seem to hurt anything to keep processing, though. + + this._input_buffer.push.apply( this._input_buffer, input ); + } + + /** + * **STOP!** You probably want to `skip()` an Offer rather than + * `abort()`. See below. + * + * Abort the current session by sending the ZMODEM abort sequence. + * This function will cause the Session object to refuse to send + * any further data. + * + * Zmodem.Sentry is configured to send all output to the terminal + * after a session’s `abort()`. That could result in lots of + * ZMODEM garble being sent to the JavaScript terminal, which you + * probably don’t want. + * + * `skip()` on an Offer is better because Session will continue to + * discard data until we reach either another file or the + * sender-initiated end of the ZMODEM session. So no ZMODEM garble, + * and the session will end successfully. + * + * The behavior of `abort()` is subject to change since it’s not + * very useful as currently implemented. + */ + abort() { + + //this._expect_abort = true; + + //From Forsberg: + // + //The Cancel sequence consists of eight CAN characters + //and ten backspace characters. ZMODEM only requires five + //Cancel characters; the other three are "insurance". + //The trailing backspace characters attempt to erase + //the effects of the CAN characters if they are + //received by a command interpreter. + // + //FG: Since we assume our connection is reliable, there’s + //no reason to send more than 5 CANs. + this._sender( + ABORT_SEQUENCE.concat([ BS, BS, BS, BS, BS ]) + ); + + this._aborted = true; + this._sender = function() { + throw new Zmodem.Error('already_aborted'); + }; + + this._on_session_end(); + + return; + } + + //---------------------------------------------------------------------- + _on_session_end() { + this._Happen("session_end"); + } + + _on_receive(hdr_or_pkt) { + this._Happen("receive", hdr_or_pkt); + } + + _before_consume() {} +} + +function _trim_OO(array) { + if (0 === Zmodem.ZMLIB.find_subarray(array, OVER_AND_OUT)) { + array.splice(0, OVER_AND_OUT.length); + } + + //TODO: This assumes OVER_AND_OUT is 2 bytes long. No biggie, but. + else if ( array[0] === OVER_AND_OUT[ OVER_AND_OUT.length - 1 ] ) { + array.splice(0, 1); + } + + return array; +} + +/** A class for ZMODEM receive sessions. + * + * @extends Session + */ +Zmodem.Session.Receive = class ZmodemReceiveSession extends Zmodem.Session { + //We only get 1 file at a time, so on each consume() either + //continue state for the current file or start a new one. + + /** + * Not called directly. + */ + constructor() { + super(); + + this._Add_event("offer"); + this._Add_event("data_in"); + this._Add_event("file_end"); + } + + /** + * Consume input bytes from the sender. + * + * @private + * @param {number[]} octets - The bytes to consume. + */ + _before_consume(octets) { + if (this._bytes_after_OO) { + throw "PROTOCOL: Session is completed!"; + } + + //Put this here so that our logic later on has access to the + //input string and can populate _bytes_after_OO when the + //session ends. + this._bytes_being_consumed = octets; + } + + /** + * Return any bytes that have been `consume()`d but + * came after the end of the ZMODEM session. + * + * @returns {number[]} The trailing bytes. + */ + get_trailing_bytes() { + if (this._aborted) return []; + + if (!this._bytes_after_OO) { + throw "PROTOCOL: Session is not completed!"; + } + + return this._bytes_after_OO.slice(0); + } + + _has_ended() { return this.aborted() || !!this._bytes_after_OO } + + //Receiver always sends hex headers. + _get_header_formatter() { return "to_hex" } + + _parse_and_consume_subpacket() { + var parse_func; + if (this._last_header_crc === 16) { + parse_func = "parse16"; + } + else { + parse_func = "parse32"; + } + + var subpacket = Zmodem.Subpacket[parse_func](this._input_buffer); + + if (subpacket) { + if (Zmodem.DEBUG) { + console.debug(this.type, "RECEIVED SUBPACKET", subpacket); + } + + this._consume_data(subpacket); + + //What state are we in if the subpacket indicates frame end + //but we haven’t gotten ZEOF yet? Can anything other than ZEOF + //follow after a ZDATA? + if (subpacket.frame_end()) { + this._next_subpacket_handler = null; + } + } + + return subpacket; + } + + _consume_first() { + if (this._got_ZFIN) { + if (this._input_buffer.length < 2) return; + + // some lrzsz don't send OO after ZFIN + // whether there's OO or not, we're done + this._bytes_after_OO = _trim_OO(this._bytes_being_consumed.slice(0)); + this._on_session_end(); + return; + + //if it’s OO, then set this._bytes_after_OO + // if (Zmodem.ZMLIB.find_subarray(this._input_buffer, OVER_AND_OUT) === 0) { + + //This doubles as an indication that the session has ended. + //We need to set this right away so that handlers like + //"session_end" will have access to it. + // this._bytes_after_OO = _trim_OO(this._bytes_being_consumed.slice(0)); + // this._on_session_end(); + // + // return; + // } + // else { + // throw( "PROTOCOL: Only thing after ZFIN should be “OO” (79,79), not: " + this._input_buffer.join() ); + // } + } + + var parsed; + do { + if (this._next_subpacket_handler) { + parsed = this._parse_and_consume_subpacket(); + } + else { + parsed = this._parse_and_consume_header(); + } + } while (parsed && this._input_buffer.length); + } + + _consume_data(subpacket) { + this._on_receive(subpacket); + + if (!this._next_subpacket_handler) { + throw( "PROTOCOL: Received unexpected data packet after " + this._last_header_name + " header: " + subpacket.get_payload().join() ); + } + + this._next_subpacket_handler.call(this, subpacket); + } + + _octets_to_string(octets) { + if (!this._textdecoder) { + this._textdecoder = new Zmodem.Text.Decoder(); + } + + return this._textdecoder.decode( new Uint8Array(octets) ); + } + + _consume_ZFILE_data(hdr, subpacket) { + if (this._file_info) { + throw "PROTOCOL: second ZFILE data subpacket received"; + } + + var packet_payload = subpacket.get_payload(); + var nul_at = packet_payload.indexOf(0); + + // + var fname = this._octets_to_string( packet_payload.slice(0, nul_at) ); + var the_rest = this._octets_to_string( packet_payload.slice( 1 + nul_at ) ).split(" "); + + var mtime = the_rest[1] && parseInt( the_rest[1], 8 ) || undefined; + if (mtime) { + mtime = new Date(mtime * 1000); + } + + this._file_info = { + name: fname, + size: the_rest[0] ? parseInt( the_rest[0], 10 ) : null, + mtime: mtime || null, + mode: the_rest[2] && parseInt( the_rest[2], 8 ) || null, + serial: the_rest[3] && parseInt( the_rest[3], 10 ) || null, + + files_remaining: the_rest[4] ? parseInt( the_rest[4], 10 ) : null, + bytes_remaining: the_rest[5] ? parseInt( the_rest[5], 10 ) : null, + }; + + //console.log("ZFILE", hdr); + + var xfer = new Offer( + hdr.get_options(), + this._file_info, + this._accept.bind(this), + this._skip.bind(this) + ); + this._current_transfer = xfer; + + //this._Happen("offer", xfer); + } + + _consume_ZDATA_data(subpacket) { + if (!this._accepted_offer) { + throw "PROTOCOL: Received data without accepting!"; + } + + //TODO: Probably should include some sort of preventive against + //infinite loop here: if the peer hasn’t sent us what we want after, + //say, 10 ZRPOS headers then we should send ZABORT and just end. + if (!this._offset_ok) { + console.warn("offset not ok!"); + _send_ZRPOS(); + return; + } + + this._file_offset += subpacket.get_payload().length; + this._on_data_in(subpacket); + + /* + console.warn("received error from data_in callback; retrying", e); + throw "unimplemented"; + */ + + if (subpacket.ack_expected() && !subpacket.frame_end()) { + this._send_header( "ZACK", Zmodem.ENCODELIB.pack_u32_le(this._file_offset) ); + } + } + + _make_promise_for_between_files() { + var sess = this; + + return new Promise( function(res) { + var between_files_handler = { + ZFILE: function(hdr) { + this._next_subpacket_handler = function(subpacket) { + this._next_subpacket_handler = null; + this._consume_ZFILE_data(hdr, subpacket); + this._Happen("offer", this._current_transfer); + res(this._current_transfer); + }; + }, + + //We use this as a keep-alive. Maybe other + //implementations do, too? + ZSINIT: function(hdr) { + //The content of this header doesn’t affect us + //since all it does is tell us details of how + //the sender will ZDLE-encode binary data. Our + //ZDLE parser doesn’t need to know in advance. + + sess._next_subpacket_handler = function(spkt) { + sess._next_subpacket_handler = null; + sess._consume_ZSINIT_data(spkt); + sess._send_header('ZACK'); + sess._next_header_handler = between_files_handler; + }; + }, + + ZFIN: function() { + this._consume_ZFIN(); + res(); + }, + }; + + sess._next_header_handler = between_files_handler; + } ); + } + + _consume_ZSINIT_data(spkt) { + + //TODO: Should this be used when we signal a cancellation? + this._attn = spkt.get_payload(); + } + + /** + * Start the ZMODEM session by signaling to the sender that + * we are ready for the first file offer. + * + * @returns {Promise} A promise that resolves with an Offer object + * or, if the sender closes the session immediately without offering + * anything, nothing. + */ + start() { + if (this._started) throw "Already started!"; + this._started = true; + + var ret = this._make_promise_for_between_files(); + + this._send_ZRINIT(); + + return ret; + } + + //Returns a promise that’s fulfilled when the file + //transfer is done. + // + // That ZEOF promise return is another promise that’s + // fulfilled when we get either ZFIN or another ZFILE. + _accept(offset) { + this._accepted_offer = true; + this._file_offset = offset || 0; + + var sess = this; + + var ret = new Promise( function(resolve_accept) { + var last_ZDATA; + + sess._next_header_handler = { + ZDATA: function on_ZDATA(hdr) { + this._consume_ZDATA(hdr); + + this._next_subpacket_handler = this._consume_ZDATA_data; + + this._next_header_handler = { + ZEOF: function on_ZEOF(hdr) { + + // Do this first to verify the ZEOF. + // This also fires the “file_end” event. + this._consume_ZEOF(hdr); + + this._next_subpacket_handler = null; + + // We don’t care about this promise. + // Prior to v0.1.8 we did because we called + // resolve_accept() at the resolution of this + // promise, but that was a bad idea and was + // never documented, so 0.1.8 changed it. + this._make_promise_for_between_files(); + + resolve_accept(); + + this._send_ZRINIT(); + }, + }; + }, + }; + } ); + + this._send_ZRPOS(); + + return ret; + } + + _skip() { + var ret = this._make_promise_for_between_files(); + + if (this._accepted_offer) { + // There’s a race condition where we might attempt to + // skip() an in-progress transfer near its end but actually + // the skip() will fire after the transfer is complete. + // While there might be ways to prevent this, they likely + // would require extra work on the part of implementations. + // + // It seems far simpler just to make this function a no-op + // in these cases. + if (!this._current_transfer) return; + + //For cancel of an in-progress transfer from lsz, + //it’s necessary to avoid this buffer overflow bug: + // + // https://github.com/gooselinux/lrzsz/blob/master/lrzsz-0.12.20.patch + // + //… which we do by asking for CRC32 from lsz. + + //We might or might not have consumed ZDATA. + //The sender also might or might not send a ZEOF before it + //parses the ZSKIP. Thus, we want to ignore the following: + // + // - ZDATA + // - ZDATA then ZEOF + // - ZEOF + // + //… and just look for the next between-file header. + + var bound_make_promise_for_between_files = function() { + + //Once this happens we fail on any received data packet. + //So it needs not to happen until we’ve received a header. + this._accepted_offer = false; + this._next_subpacket_handler = null; + + this._make_promise_for_between_files(); + }.bind(this); + + Object.assign( + this._next_header_handler, + { + ZEOF: bound_make_promise_for_between_files, + ZDATA: function() { + bound_make_promise_for_between_files(); + this._next_header_handler.ZEOF = bound_make_promise_for_between_files; + }.bind(this), + } + ); + } + + //this._accepted_offer = false; + + this._file_info = null; + + this._send_header( "ZSKIP" ); + + return ret; + } + + _send_ZRINIT() { + this._send_header( "ZRINIT", ZRINIT_FLAGS ); + } + + _consume_ZFIN() { + this._got_ZFIN = true; + this._send_header( "ZFIN" ); + } + + _consume_ZEOF(header) { + if (this._file_offset !== header.get_offset()) { + throw( "ZEOF offset mismatch; unimplemented (local: " + this._file_offset + "; ZEOF: " + header.get_offset() + ")" ); + } + + this._on_file_end(); + + //Preserve these two so that file_end callbacks + //will have the right information. + this._file_info = null; + this._current_transfer = null; + } + + _consume_ZDATA(header) { + if ( this._file_offset === header.get_offset() ) { + this._offset_ok = true; + } + else { + throw "Error correction is unimplemented."; + } + } + + _send_ZRPOS() { + this._send_header( "ZRPOS", this._file_offset ); + } + + //---------------------------------------------------------------------- + //events + + _on_file_end() { + this._Happen("file_end"); + + if (this._current_transfer) { + this._current_transfer._Happen("complete"); + this._current_transfer = null; + } + } + + _on_data_in(subpacket) { + this._Happen("data_in", subpacket); + + if (this._current_transfer) { + this._current_transfer._Happen("input", subpacket.get_payload()); + } + } +} + +Object.assign( + Zmodem.Session.Receive.prototype, + { + type: "receive", + } +); + +//---------------------------------------------------------------------- + +/** + * @typedef {Object} FileDetails + * + * @property {string} name - The name of the file. + * + * @property {number} [size] - The file size, in bytes. + * + * @property {number} [mode] - The file mode (e.g., 0100644). + * + * @property {Date|number} [mtime] - The file’s modification time. + * When expressed as a number, the unit is epoch seconds. + * + * @property {number} [files_remaining] - Inclusive of the current file, + * so this value is never less than 1. + * + * @property {number} [bytes_remaining] - Inclusive of the current file. + */ + +/** + * Common methods for Transfer and Offer objects. + * + * @mixin + */ +var Transfer_Offer_Mixin = { + /** + * Returns the file details object. + * @returns {FileDetails} `mtime` is a Date. + */ + get_details: function get_details() { + return Object.assign( {}, this._file_info ); + }, + + /** + * Returns a parse of the ZFILE header’s payload. + * + * @returns {Object} Members are: + * + * - `conversion` (string | undefined) + * - `management` (string | undefined) + * - `transfer` (string | undefined) + * - `sparse` (boolean) + */ + get_options: function get_options() { + return Object.assign( {}, this._zfile_opts ); + }, + + /** + * Returns the offset based on the last transferred chunk. + * @returns {number} The file offset (i.e., number of bytes after + * the start of the file). + */ + get_offset: function get_offset() { + return this._file_offset; + }, +}; + +/** + * A class to represent a sender’s interaction with a single file + * transfer within a batch. When a receiver accepts an offer, the + * Session instantiates this class and passes the instance as the + * promise resolution from send_offer(). + * + * @mixes Transfer_Offer_Mixin + */ +class Transfer { + + /** + * Not called directly. + */ + constructor(file_info, offset, send_func, end_func) { + this._file_info = file_info; + this._file_offset = offset || 0; + + this._send = send_func; + this._end = end_func; + } + + /** + * Send a (non-terminal) piece of the file. + * + * @param { number[] | Uint8Array } array_like - The bytes to send. + */ + send(array_like) { + this._send(array_like); + this._file_offset += array_like.length; + } + + /** + * Complete the file transfer. + * + * @param { number[] | Uint8Array } [array_like] - The last bytes to send. + * + * @return { Promise } Resolves when the receiver has indicated + * acceptance of the end of the file transfer. + */ + end(array_like) { + var ret = this._end(array_like || []); + if (array_like) this._file_offset += array_like.length; + return ret; + } +} +Object.assign( Transfer.prototype, Transfer_Offer_Mixin ); + +/** + * A class to represent a receiver’s interaction with a single file + * transfer offer within a batch. There is functionality here to + * skip or accept offered files and either to spool the packet + * payloads or to handle them yourself. + * + * @mixes Transfer_Offer_Mixin + */ +class Offer extends _Eventer { + + /** + * Not called directly. + */ + constructor(zfile_opts, file_info, accept_func, skip_func) { + super(); + + this._zfile_opts = zfile_opts; + this._file_info = file_info; + + this._accept_func = accept_func; + this._skip_func = skip_func; + + this._Add_event("input"); + this._Add_event("complete"); + + //Register this first so that application handlers receive + //the updated offset. + this.on("input", this._input_handler); + } + + _verify_not_skipped() { + if (this._skipped) { + throw new Zmodem.Error("Already skipped!"); + } + } + + /** + * Tell the sender that you don’t want the offered file. + * + * You can send this in lieu of `accept()` or after it, e.g., + * if you find that the transfer is taking too long. Note that, + * if you `skip()` after you `accept()`, you’ll likely have to + * wait for buffers to clear out. + * + */ + skip() { + this._verify_not_skipped(); + this._skipped = true; + + return this._skip_func.apply(this, arguments); + } + + /** + * Tell the sender to send the offered file. + * + * @param {Object} [opts] - Can be: + * @param {string} [opts.oninput=spool_uint8array] - Can be: + * + * - `spool_uint8array`: Stores the ZMODEM + * packet payloads as Uint8Array instances. + * This makes for an easy transition to a Blob, + * which JavaScript can use to save the file to disk. + * + * - `spool_array`: Stores the ZMODEM packet payloads + * as Array instances. Each value is an octet value. + * + * - (function): A handler that receives each payload + * as it arrives. The Offer object does not store + * the payloads internally when thus configured. + * + * @return { Promise } Resolves when the file is fully received. + * If the Offer has been spooling + * the packet payloads, the promise resolves with an Array + * that contains those payloads. + */ + accept(opts) { + this._verify_not_skipped(); + + if (this._accepted) { + throw new Zmodem.Error("Already accepted!"); + } + this._accepted = true; + + if (!opts) opts = {}; + + this._file_offset = opts.offset || 0; + + switch (opts.on_input) { + case null: + case undefined: + case "spool_array": + case DEFAULT_RECEIVE_INPUT_MODE: //default + this._spool = []; + break; + default: + if (typeof opts.on_input !== "function") { + throw "Invalid “on_input”: " + opts.on_input; + } + } + + this._input_handler_mode = opts.on_input || DEFAULT_RECEIVE_INPUT_MODE; + + return this._accept_func(this._file_offset).then( this._get_spool.bind(this) ); + } + + _input_handler(payload) { + this._file_offset += payload.length; + + if (typeof this._input_handler_mode === "function") { + this._input_handler_mode(payload); + } + else { + if (this._input_handler_mode === DEFAULT_RECEIVE_INPUT_MODE) { + payload = new Uint8Array(payload); + } + + //sanity + else if (this._input_handler_mode !== "spool_array") { + throw new Zmodem.Error("WTF?? _input_handler_mode = " + this._input_handler_mode); + } + + this._spool.push(payload); + } + } + + _get_spool() { + return this._spool; + } +} +Object.assign( Offer.prototype, Transfer_Offer_Mixin ); + +//Curious that ZSINIT isn’t here … but, lsz sends it as hex. +const SENDER_BINARY_HEADER = { + ZFILE: true, + ZDATA: true, +}; + +/** + * A class that encapsulates behavior for a ZMODEM sender. + * + * @extends Session + */ +Zmodem.Session.Send = class ZmodemSendSession extends Zmodem.Session { + + /** + * Not called directly. + */ + constructor(zrinit_hdr) { + super(); + + if (!zrinit_hdr) { + throw "Need first header!"; + } + else if (zrinit_hdr.NAME !== "ZRINIT") { + throw("First header should be ZRINIT, not " + zrinit_hdr.NAME); + } + + this._last_header_name = 'ZRINIT'; + + //We don’t need to send crc32. Even if the other side can grok it, + //there’s no point to sending it since, for now, we assume we’re + //on a reliable connection, e.g., TCP. Ideally we’d just forgo + //CRC checks completely, but ZMODEM doesn’t allow that. + // + //If we *were* to start using crc32, we’d update this every time + //we send a header. + this._subpacket_encode_func = 'encode16'; + + this._zencoder = new Zmodem.ZDLE(); + + this._consume_ZRINIT(zrinit_hdr); + + this._file_offset = 0; + + var zrqinit_count = 0; + + this._start_keepalive_on_set_sender = true; + + //lrzsz will send ZRINIT until it gets an offer. (keep-alive?) + //It sends 4 additional ones after the initial ZRINIT and, if + //no response is received, starts sending “C” (0x43, 67) as if to + //try to downgrade to XMODEM or YMODEM. + //var sess = this; + //this._prepare_to_receive_ZRINIT( function keep_alive() { + // sess._prepare_to_receive_ZRINIT(keep_alive); + //} ); + + //queue up the ZSINIT flag to send -- but seems useless?? + + /* + Object.assign( + this._on_evt, + { + file_received: [], + }, + }; + */ + } + + /** + * Sets the sender function. The first time this is called, + * it will also initiate a keepalive using ZSINIT until the + * first file is sent. + * + * @param {Function} func - The function to call. + * It will receive an Array with the relevant octets. + * + * @return {Session} The session object (for chaining). + */ + set_sender(func) { + super.set_sender(func); + + if (this._start_keepalive_on_set_sender) { + this._start_keepalive_on_set_sender = false; + this._start_keepalive(); + } + + return this; + } + + //7.3.3 .. The sender also uses hex headers when they are + //not followed by binary data subpackets. + // + //FG: … or when the header is ZSINIT? That’s what lrzsz does, anyway. + //Then it sends a single NUL byte as the payload to an end_ack subpacket. + _get_header_formatter(name) { + return SENDER_BINARY_HEADER[name] ? "to_binary16" : "to_hex"; + } + + //In order to keep lrzsz from timing out, we send ZSINIT every 5 seconds. + //Maybe make this configurable? + _start_keepalive() { + //if (this._keepalive_promise) throw "Keep-alive already started!"; + if (!this._keepalive_promise) { + var sess = this; + + this._keepalive_promise = new Promise(function(resolve) { + //console.log("SETTING KEEPALIVE TIMEOUT"); + sess._keepalive_timeout = setTimeout(resolve, KEEPALIVE_INTERVAL); + }).then( function() { + sess._next_header_handler = { + ZACK: function() { + + //We’re going to need to ensure that the + //receiver is ready for all control characters + //to be escaped. If we’ve already sent a ZSINIT + //and gotten a response, then we know that that + //work is already done later on when we actually + //send an offer. + sess._got_ZSINIT_ZACK = true; + }, + }; + sess._send_ZSINIT(); + + sess._keepalive_promise = null; + sess._start_keepalive(); + }); + } + } + + _stop_keepalive() { + if (this._keepalive_promise) { + //console.log("STOPPING KEEPALIVE"); + clearTimeout(this._keepalive_timeout); + this._keep_alive_promise = null; + } + } + + _send_ZSINIT() { + //See note at _ensure_receiver_escapes_ctrl_chars() + //for why we have to pass ESCCTL. + + var zsinit_flags = []; + if (this._zencoder.escapes_ctrl_chars()) { + zsinit_flags.push("ESCCTL"); + } + + this._send_header_and_data( + ["ZSINIT", zsinit_flags], + [0], + "end_ack" + ); + } + + _consume_ZRINIT(hdr) { + this._last_ZRINIT = hdr; + + if (hdr.get_buffer_size()) { + throw( "Buffer size (" + hdr.get_buffer_size() + ") is unsupported!" ); + } + + if (!hdr.can_full_duplex()) { + throw( "Half-duplex I/O is unsupported!" ); + } + + if (!hdr.can_overlap_io()) { + throw( "Non-overlap I/O is unsupported!" ); + } + + if (hdr.escape_8th_bit()) { + throw( "8-bit escaping is unsupported!" ); + } + + if (FORCE_ESCAPE_CTRL_CHARS) { + this._zencoder.set_escape_ctrl_chars(true); + if (!hdr.escape_ctrl_chars()) { + console.debug("Peer didn’t request escape of all control characters. Will send ZSINIT to force recognition of escaped control characters."); + } + } + else { + this._zencoder.set_escape_ctrl_chars(hdr.escape_ctrl_chars()); + } + } + + //https://stackoverflow.com/questions/23155939/missing-0xf-and-0x16-when-binary-data-through-virtual-serial-port-pair-created-b + //^^ Because of that, we always escape control characters. + //The alternative would be that lrz would never receive those + //two bytes from zmodem.js. + _ensure_receiver_escapes_ctrl_chars() { + var promise; + + var needs_ZSINIT = !this._last_ZRINIT.escape_ctrl_chars() && !this._got_ZSINIT_ZACK; + + if (needs_ZSINIT) { + var sess = this; + promise = new Promise( function(res) { + sess._next_header_handler = { + ZACK: (hdr) => { + res(); + }, + }; + sess._send_ZSINIT(); + } ); + } + else { + promise = Promise.resolve(); + } + + return promise; + } + + _convert_params_to_offer_payload_array(params) { + params = Zmodem.Validation.offer_parameters(params); + + var subpacket_payload = params.name + "\x00"; + + var subpacket_space_pieces = [ + (params.size || 0).toString(10), + params.mtime ? params.mtime.toString(8) : "0", + params.mode ? (0x8000 | params.mode).toString(8) : "0", + "0", //serial + ]; + + if (params.files_remaining) { + subpacket_space_pieces.push( params.files_remaining ); + + if (params.bytes_remaining) { + subpacket_space_pieces.push( params.bytes_remaining ); + } + } + + subpacket_payload += subpacket_space_pieces.join(" "); + return this._string_to_octets(subpacket_payload); + } + + /** + * Send an offer to the receiver. + * + * @param {FileDetails} params - All about the file you want to transfer. + * + * @returns {Promise} If the receiver accepts the offer, then the + * resolution is a Transfer object; otherwise the resolution is + * undefined. + */ + send_offer(params) { + if (Zmodem.DEBUG) { + console.debug("SENDING OFFER", params); + } + + if (!params) throw "need file params!"; + + if (this._sending_file) throw "Already sending file!"; + + var payload_array = this._convert_params_to_offer_payload_array(params); + + this._stop_keepalive(); + + var sess = this; + + function zrpos_handler_setter_func() { + sess._next_header_handler = { + + // The receiver may send ZRPOS in at least two cases: + // + // 1) A malformed subpacket arrived, so we need to + // “rewind” a bit and continue from the receiver’s + // last-successful location in the file. + // + // 2) The receiver hasn’t gotten any data for a bit, + // so it sends ZRPOS as a “ping”. + // + // Case #1 shouldn’t happen since zmodem.js requires a + // reliable transport. Case #2, though, can happen due + // to either normal network congestion or errors in + // implementation. In either case, there’s nothing for + // us to do but to ignore the ZRPOS, with an optional + // warning. + // + ZRPOS: function(hdr) { + if (Zmodem.DEBUG) { + console.warn("Mid-transfer ZRPOS … implementation error?"); + } + + zrpos_handler_setter_func(); + }, + }; + }; + + var doer_func = function() { + + //return Promise object that is fulfilled when the ZRPOS or ZSKIP arrives. + //The promise value is the byte offset, or undefined for ZSKIP. + //If ZRPOS arrives, then send ZDATA(0) and set this._sending_file. + var handler_setter_promise = new Promise( function(res) { + sess._next_header_handler = { + ZSKIP: function() { + sess._start_keepalive(); + res(); + }, + ZRPOS: function(hdr) { + sess._sending_file = true; + + zrpos_handler_setter_func(); + + res( + new Transfer( + params, + hdr.get_offset(), + sess._send_interim_file_piece.bind(sess), + sess._end_file.bind(sess) + ) + ); + }, + }; + } ); + + sess._send_header_and_data( ["ZFILE"], payload_array, "end_ack" ); + + delete sess._sent_ZDATA; + + return handler_setter_promise; + }; + + if (FORCE_ESCAPE_CTRL_CHARS) { + return this._ensure_receiver_escapes_ctrl_chars().then(doer_func); + } + + return doer_func(); + } + + _send_header_and_data( hdr_name_and_args, data_arr, frameend ) { + var bytes_hdr = this._create_header_bytes(hdr_name_and_args); + + var data_bytes = this._build_subpacket_bytes(data_arr, frameend); + + bytes_hdr[0].push.apply( bytes_hdr[0], data_bytes ); + + if (Zmodem.DEBUG) { + this._log_header( "SENDING HEADER", bytes_hdr[1] ); + console.debug( this.type, "-- HEADER PAYLOAD:", frameend, data_bytes.length ); + } + + this._sender( bytes_hdr[0] ); + + this._last_sent_header = bytes_hdr[1]; + } + + _build_subpacket_bytes( bytes_arr, frameend ) { + var subpacket = Zmodem.Subpacket.build(bytes_arr, frameend); + + return subpacket[this._subpacket_encode_func]( this._zencoder ); + } + + _build_and_send_subpacket( bytes_arr, frameend ) { + this._sender( this._build_subpacket_bytes(bytes_arr, frameend) ); + } + + _string_to_octets(string) { + if (!this._textencoder) { + this._textencoder = new Zmodem.Text.Encoder(); + } + + var uint8arr = this._textencoder.encode(string); + return Array.prototype.slice.call(uint8arr); + } + + /* + Potential future support for responding to ZRPOS: + send_file_offset(offset) { + } + */ + + /* + Sending logic works thus: + - ASSUME the receiver can overlap I/O (CANOVIO) + (so fail if !CANFDX || !CANOVIO) + - Sender opens the firehose … all ZCRCG (!end/!ack) + until the end, when we send a ZCRCE (end/!ack) + NB: try 8k/32k/64k chunk sizes? Looks like there’s + no need to change the packet otherwise. + */ + //TODO: Put this on a Transfer object similar to what Receive uses? + _send_interim_file_piece(bytes_obj) { + + //We don’t ask the receiver to confirm because there’s no need. + this._send_file_part(bytes_obj, "no_end_no_ack"); + + //This pattern will allow + //error-correction without buffering the entire stream in JS. + //For now the promise is always resolved, but in the future we + //can make it only resolve once we’ve gotten acknowledgement. + return Promise.resolve(); + } + + _ensure_we_are_sending() { + if (!this._sending_file) throw "Not sending a file currently!"; + } + + //This resolves once we receive ZEOF. + _end_file(bytes_obj) { + this._ensure_we_are_sending(); + + //Is the frame-end-ness of this last packet redundant + //with the ZEOF packet?? - No. It signals the receiver that + //the next thing to expect is a header, not a packet. + + //no-ack, following lrzsz’s example + this._send_file_part(bytes_obj, "end_no_ack"); + + var sess = this; + + //Register this before we send ZEOF in case of local round-trip. + //(Basically just for synchronous testing, but.) + var ret = new Promise( function(res) { + //console.log("UNSETTING SENDING FLAG"); + sess._sending_file = false; + sess._prepare_to_receive_ZRINIT(res); + } ); + + this._send_header( "ZEOF", this._file_offset ); + + this._file_offset = 0; + + return ret; + } + + //Called at the beginning of our session + //and also when we’re done sending a file. + _prepare_to_receive_ZRINIT(after_consume) { + this._next_header_handler = { + ZRINIT: function(hdr) { + this._consume_ZRINIT(hdr); + if (after_consume) after_consume(); + }, + }; + } + + /** + * Signal to the receiver that the ZMODEM session is wrapping up. + * + * @returns {Promise} Resolves when the receiver has responded to + * our signal that the session is over. + */ + close() { + var ok_to_close = (this._last_header_name === "ZRINIT") + if (!ok_to_close) { + ok_to_close = (this._last_header_name === "ZSKIP"); + } + if (!ok_to_close) { + ok_to_close = (this._last_sent_header.name === "ZSINIT") && (this._last_header_name === "ZACK"); + } + + if (!ok_to_close) { + throw( "Can’t close; last received header was “" + this._last_header_name + "”" ); + } + + var sess = this; + + var ret = new Promise( function(res, rej) { + sess._next_header_handler = { + ZFIN: function() { + sess._sender( OVER_AND_OUT ); + sess._sent_OO = true; + sess._on_session_end(); + res(); + }, + }; + } ); + + this._send_header("ZFIN"); + + return ret; + } + + _has_ended() { + return this.aborted() || !!this._sent_OO; + } + + _send_file_part(bytes_obj, final_packetend) { + if (!this._sent_ZDATA) { + this._send_header( "ZDATA", this._file_offset ); + this._sent_ZDATA = true; + } + + var obj_offset = 0; + + var bytes_count = bytes_obj.length; + + //We have to go through at least once in event of an + //empty buffer, e.g., an empty end_file. + while (true) { + var chunk_size = Math.min(obj_offset + MAX_CHUNK_LENGTH, bytes_count) - obj_offset; + + var at_end = (chunk_size + obj_offset) >= bytes_count; + + var chunk = bytes_obj.slice( obj_offset, obj_offset + chunk_size ); + if (!(chunk instanceof Array)) { + chunk = Array.prototype.slice.call(chunk); + } + + this._build_and_send_subpacket( + chunk, + at_end ? final_packetend : "no_end_no_ack" + ); + + this._file_offset += chunk_size; + obj_offset += chunk_size; + + if (obj_offset >= bytes_count) break; + } + } + + _consume_first() { + if (!this._parse_and_consume_header()) { + + //When the ZMODEM receive program starts, it immediately sends + //a ZRINIT header to initiate ZMODEM file transfers, or a + //ZCHALLENGE header to verify the sending program. The receive + //program resends its header at response time (default 10 second) + //intervals for a suitable period of time (40 seconds total) + //before falling back to YMODEM protocol. + if (this._input_buffer.join() === "67") { + throw "Receiver has fallen back to YMODEM."; + } + } + } + + _on_session_end() { + this._stop_keepalive(); + super._on_session_end(); + } +} + +Object.assign( + Zmodem.Session.Send.prototype, + { + type: "send", + } +); diff --git a/web/src/vendors/zmodem.js/zsubpacket.js b/web/src/vendors/zmodem.js/zsubpacket.js new file mode 100644 index 0000000..f77a527 --- /dev/null +++ b/web/src/vendors/zmodem.js/zsubpacket.js @@ -0,0 +1,241 @@ +"use strict"; + +var Zmodem = module.exports; + +Object.assign( + Zmodem, + require("./zcrc"), + require("./zdle"), + require("./zmlib"), + require("./zerror") +); + +const + ZCRCE = 0x68, // 'h', 104, frame ends, header packet follows + ZCRCG = 0x69, // 'i', 105, frame continues nonstop + ZCRCQ = 0x6a, // 'j', 106, frame continues, ZACK expected + ZCRCW = 0x6b // 'k', 107, frame ends, ZACK expected +; + +var SUBPACKET_BUILDER; + +/** Class that represents a ZMODEM data subpacket. */ +Zmodem.Subpacket = class ZmodemSubpacket { + + /** + * Build a Subpacket subclass given a payload and frame end string. + * + * @param {Array} octets - The octet values to parse. + * Each array member should be an 8-bit unsigned integer (0-255). + * + * @param {string} frameend - One of: + * - `no_end_no_ack` + * - `end_no_ack` + * - `no_end_ack` (unused currently) + * - `end_ack` + * + * @returns {Subpacket} An instance of the appropriate Subpacket subclass. + */ + static build(octets, frameend) { + + //TODO: make this better + var Ctr = SUBPACKET_BUILDER[frameend]; + if (!Ctr) { + throw("No subpacket type “" + frameend + "” is defined! Try one of: " + Object.keys(SUBPACKET_BUILDER).join(", ")); + } + + return new Ctr(octets); + } + + /** + * Return the octet values array that represents the object + * encoded with a 16-bit CRC. + * + * @param {ZDLE} zencoder - A ZDLE instance to use for ZDLE encoding. + * + * @returns {number[]} An array of octet values suitable for sending + * as binary data. + */ + encode16(zencoder) { + return this._encode( zencoder, Zmodem.CRC.crc16 ); + } + + /** + * Return the octet values array that represents the object + * encoded with a 32-bit CRC. + * + * @param {ZDLE} zencoder - A ZDLE instance to use for ZDLE encoding. + * + * @returns {number[]} An array of octet values suitable for sending + * as binary data. + */ + encode32(zencoder) { + return this._encode( zencoder, Zmodem.CRC.crc32 ); + } + + /** + * Return the subpacket payload’s octet values. + * + * NOTE: For speed, this returns the actual data in the subpacket; + * if you mutate this return value, you alter the Subpacket object + * internals. This is OK if you won’t need the Subpacket anymore, but + * just be careful. + * + * @returns {number[]} The subpacket’s payload, represented as an + * array of octet values. **DO NOT ALTER THIS ARRAY** unless you + * no longer need the Subpacket. + */ + get_payload() { return this._payload } + + /** + * Parse out a Subpacket object from a given array of octet values, + * assuming a 16-bit CRC. + * + * An exception is thrown if the given bytes are definitively invalid + * as subpacket values with 16-bit CRC. + * + * @param {number[]} octets - The octet values to parse. + * Each array member should be an 8-bit unsigned integer (0-255). + * This object is mutated in the function. + * + * @returns {Subpacket|undefined} An instance of the appropriate Subpacket + * subclass, or undefined if not enough octet values are given + * to determine whether there is a valid subpacket here or not. + */ + static parse16(octets) { + return ZmodemSubpacket._parse(octets, 2); + } + + //parse32 test: + //[102, 105, 108, 101, 110, 97, 109, 101, 119, 105, 116, 104, 115, 112, 97, 99, 101, 115, 0, 49, 55, 49, 51, 49, 52, 50, 52, 51, 50, 49, 55, 50, 49, 48, 48, 54, 52, 52, 48, 49, 49, 55, 0, 43, 8, 63, 115, 23, 17] + + /** + * Same as parse16(), but assuming a 32-bit CRC. + * + * @param {number[]} octets - The octet values to parse. + * Each array member should be an 8-bit unsigned integer (0-255). + * This object is mutated in the function. + * + * @returns {Subpacket|undefined} An instance of the appropriate Subpacket + * subclass, or undefined if not enough octet values are given + * to determine whether there is a valid subpacket here or not. + */ + static parse32(octets) { + return ZmodemSubpacket._parse(octets, 4); + } + + /** + * Not used directly. + */ + constructor(payload) { + this._payload = payload; + } + + _encode(zencoder, crc_func) { + return zencoder.encode( this._payload.slice(0) ).concat( + [ Zmodem.ZMLIB.ZDLE, this._frameend_num ], + zencoder.encode( crc_func( this._payload.concat(this._frameend_num) ) ) + ); + } + + //Because of ZDLE encoding, we’ll never see any of the frame-end octets + //in a stream except as the ends of data payloads. + static _parse(bytes_arr, crc_len) { + + var end_at; + var creator; + + //These have to be written in decimal since they’re lookup keys. + var _frame_ends_lookup = { + 104: ZEndNoAckSubpacket, + 105: ZNoEndNoAckSubpacket, + 106: ZNoEndAckSubpacket, + 107: ZEndAckSubpacket, + }; + + var zdle_at = 0; + while (zdle_at < bytes_arr.length) { + zdle_at = bytes_arr.indexOf( Zmodem.ZMLIB.ZDLE, zdle_at ); + if (zdle_at === -1) return; + + var after_zdle = bytes_arr[ zdle_at + 1 ]; + creator = _frame_ends_lookup[ after_zdle ]; + if (creator) { + end_at = zdle_at + 1; + break; + } + + zdle_at++; + } + + if (!creator) return; + + var frameend_num = bytes_arr[end_at]; + + //sanity check + if (bytes_arr[end_at - 1] !== Zmodem.ZMLIB.ZDLE) { + throw( "Byte before frame end should be ZDLE, not " + bytes_arr[end_at - 1] ); + } + + var zdle_encoded_payload = bytes_arr.splice( 0, end_at - 1 ); + + var got_crc = Zmodem.ZDLE.splice( bytes_arr, 2, crc_len ); + if (!got_crc) { + //got payload but no CRC yet .. should be rare! + + //We have to put the ZDLE-encoded payload back before returning. + bytes_arr.unshift.apply(bytes_arr, zdle_encoded_payload); + + return; + } + + var payload = Zmodem.ZDLE.decode(zdle_encoded_payload); + + //We really shouldn’t need to do this, but just for good measure. + //I suppose it’s conceivable this may run over UDP or something? + Zmodem.CRC[ (crc_len === 2) ? "verify16" : "verify32" ]( + payload.concat( [frameend_num] ), + got_crc + ); + + return new creator(payload, got_crc); + } +} + +class ZEndSubpacketBase extends Zmodem.Subpacket { + frame_end() { return true } +} +class ZNoEndSubpacketBase extends Zmodem.Subpacket { + frame_end() { return false } +} + +//Used for end-of-file. +class ZEndNoAckSubpacket extends ZEndSubpacketBase { + ack_expected() { return false } +} +ZEndNoAckSubpacket.prototype._frameend_num = ZCRCE; + +//Used for ZFILE and ZSINIT payloads. +class ZEndAckSubpacket extends ZEndSubpacketBase { + ack_expected() { return true } +} +ZEndAckSubpacket.prototype._frameend_num = ZCRCW; + +//Used for ZDATA, prior to end-of-file. +class ZNoEndNoAckSubpacket extends ZNoEndSubpacketBase { + ack_expected() { return false } +} +ZNoEndNoAckSubpacket.prototype._frameend_num = ZCRCG; + +//only used if receiver can full-duplex +class ZNoEndAckSubpacket extends ZNoEndSubpacketBase { + ack_expected() { return true } +} +ZNoEndAckSubpacket.prototype._frameend_num = ZCRCQ; + +SUBPACKET_BUILDER = { + end_no_ack: ZEndNoAckSubpacket, + end_ack: ZEndAckSubpacket, + no_end_no_ack: ZNoEndNoAckSubpacket, + no_end_ack: ZNoEndAckSubpacket, +}; diff --git a/web/src/vendors/zmodem.js/zvalidation.js b/web/src/vendors/zmodem.js/zvalidation.js new file mode 100644 index 0000000..e8618e9 --- /dev/null +++ b/web/src/vendors/zmodem.js/zvalidation.js @@ -0,0 +1,130 @@ +"use strict"; + +var Zmodem = module.exports; + +Object.assign( + Zmodem, + require("./zerror") +); + +const LOOKS_LIKE_ZMODEM_HEADER = /\*\x18[AC]|\*\*\x18B/; + +function _validate_number(key, value) { + if (value < 0) { + throw new Zmodem.Error("validation", "“" + key + "” (" + value + ") must be nonnegative."); + } + + if (value !== Math.floor(value)) { + throw new Zmodem.Error("validation", "“" + key + "” (" + value + ") must be an integer."); + } +} + +/** Validation logic for zmodem.js + * + * @exports Validation + */ +Zmodem.Validation = { + + /** + * Validates and normalizes a set of parameters for an offer to send. + * NOTE: This returns “mtime” as epoch seconds, not a Date. This is + * inconsistent with the get_details() method in Session, but it’s + * more useful for sending over the wire. + * + * @param {FileDetails} params - The file details. Some fairly trivial + * variances from the specification are allowed. + * + * @return {FileDetails} The parameters that should be sent. `mtime` + * will be a Date rather than a number. + */ + offer_parameters: function offer_parameters(params) { + if (!params.name) { + throw new Zmodem.Error("validation", "Need “name”!"); + } + + if (typeof params.name !== "string") { + throw new Zmodem.Error("validation", "“name” (" + params.name + ") must be a string!"); + } + + //So that we can override values as is useful + //without affecting the passed-in object. + params = Object.assign({}, params); + + if (LOOKS_LIKE_ZMODEM_HEADER.test(params.name)) { + console.warn("The filename " + JSON.stringify(name) + " contains characters that look like a ZMODEM header. This could corrupt the ZMODEM session; consider renaming it so that the filename doesn’t contain control characters."); + } + + if (params.serial !== null && params.serial !== undefined) { + throw new Zmodem.Error("validation", "“serial” is meaningless."); + } + + params.serial = null; + + ["size", "mode", "files_remaining", "bytes_remaining"].forEach( + function(k) { + var ok; + switch (typeof params[k]) { + case "object": + ok = (params[k] === null); + break; + case "undefined": + params[k] = null; + ok = true; + break; + case "number": + _validate_number(k, params[k]); + + ok = true; + break; + } + + if (!ok) { + throw new Zmodem.Error("validation", "“" + k + "” (" + params[k] + ") must be null, undefined, or a number."); + } + } + ); + + if (typeof params.mode === "number") { + params.mode |= 0x8000; + } + + if (params.files_remaining === 0) { + throw new Zmodem.Error("validation", "“files_remaining”, if given, must be positive."); + } + + var mtime_ok; + switch (typeof params.mtime) { + case "object": + mtime_ok = true; + + if (params.mtime instanceof Date) { + + var date_obj = params.mtime; + params.mtime = Math.floor( date_obj.getTime() / 1000 ); + if (params.mtime < 0) { + throw new Zmodem.Error("validation", "“mtime” (" + date_obj + ") must not be earlier than 1970."); + } + } + else if (params.mtime !== null) { + mtime_ok = false; + } + + break; + + case "undefined": + params.mtime = null; + mtime_ok = true; + break; + case "number": + _validate_number("mtime", params.mtime); + mtime_ok = true; + break; + } + + if (!mtime_ok) { + throw new Zmodem.Error("validation", "“mtime” (" + params.mtime + ") must be null, undefined, a Date, or a number."); + } + + return params; + }, +};