move again
This commit is contained in:
parent
4892b1f5e2
commit
6a4d4bdf4a
|
@ -10,7 +10,11 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"bedrocktool/cmd/bedrocktool/utils"
|
"github.com/bedrock-tool/bedrocktool/utils"
|
||||||
|
|
||||||
|
_ "github.com/bedrock-tool/bedrocktool/subcommands"
|
||||||
|
_ "github.com/bedrock-tool/bedrocktool/subcommands/skins"
|
||||||
|
_ "github.com/bedrock-tool/bedrocktool/subcommands/world"
|
||||||
|
|
||||||
"github.com/google/subcommands"
|
"github.com/google/subcommands"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
Binary file not shown.
8
go.mod
8
go.mod
|
@ -1,4 +1,4 @@
|
||||||
module bedrocktool
|
module github.com/bedrock-tool/bedrocktool
|
||||||
|
|
||||||
go 1.19
|
go 1.19
|
||||||
|
|
||||||
|
@ -34,9 +34,9 @@ require (
|
||||||
github.com/jinzhu/copier v0.3.5
|
github.com/jinzhu/copier v0.3.5
|
||||||
github.com/klauspost/compress v1.15.9 // indirect
|
github.com/klauspost/compress v1.15.9 // indirect
|
||||||
github.com/muhammadmuzzammil1998/jsonc v1.0.0 // indirect
|
github.com/muhammadmuzzammil1998/jsonc v1.0.0 // indirect
|
||||||
github.com/sandertv/go-raknet v1.11.1
|
github.com/sandertv/go-raknet v1.11.1 // indirect
|
||||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
github.com/sirupsen/logrus v1.9.0
|
||||||
go.uber.org/atomic v1.10.0 // indirect
|
go.uber.org/atomic v1.10.0
|
||||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
|
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
|
||||||
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539
|
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -55,6 +55,8 @@ github.com/olebeck/gophertunnel v1.24.8-2 h1:T7WY2M/GrKTOgcH1RcDiB8LNlhK+PEzGdHS
|
||||||
github.com/olebeck/gophertunnel v1.24.8-2/go.mod h1:dMOw79FHxr2azEqiGH20AwdljisAN1kqwu5SjPBnZ5k=
|
github.com/olebeck/gophertunnel v1.24.8-2/go.mod h1:dMOw79FHxr2azEqiGH20AwdljisAN1kqwu5SjPBnZ5k=
|
||||||
github.com/olebeck/gophertunnel v1.24.8-3 h1:qR5PCFWUAcUureCt36tLqaXWOjHVsFx66PiKm1obtkY=
|
github.com/olebeck/gophertunnel v1.24.8-3 h1:qR5PCFWUAcUureCt36tLqaXWOjHVsFx66PiKm1obtkY=
|
||||||
github.com/olebeck/gophertunnel v1.24.8-3/go.mod h1:dMOw79FHxr2azEqiGH20AwdljisAN1kqwu5SjPBnZ5k=
|
github.com/olebeck/gophertunnel v1.24.8-3/go.mod h1:dMOw79FHxr2azEqiGH20AwdljisAN1kqwu5SjPBnZ5k=
|
||||||
|
github.com/olebeck/gophertunnel v1.24.8-4 h1:V0Giy93JYDzR6NhtXOw/UcWpY85Jt/czp7xcAfJz22Y=
|
||||||
|
github.com/olebeck/gophertunnel v1.24.8-4/go.mod h1:dMOw79FHxr2azEqiGH20AwdljisAN1kqwu5SjPBnZ5k=
|
||||||
github.com/olebeck/gophertunnel v1.24.8 h1:jdqBOABDAE1yISqzm9IxIrI+/lJApLBjTieynXUSalw=
|
github.com/olebeck/gophertunnel v1.24.8 h1:jdqBOABDAE1yISqzm9IxIrI+/lJApLBjTieynXUSalw=
|
||||||
github.com/olebeck/gophertunnel v1.24.8/go.mod h1:dMOw79FHxr2azEqiGH20AwdljisAN1kqwu5SjPBnZ5k=
|
github.com/olebeck/gophertunnel v1.24.8/go.mod h1:dMOw79FHxr2azEqiGH20AwdljisAN1kqwu5SjPBnZ5k=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package subcommands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -10,7 +10,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"bedrocktool/cmd/bedrocktool/utils"
|
"github.com/bedrock-tool/bedrocktool/utils"
|
||||||
|
|
||||||
"github.com/google/gopacket"
|
"github.com/google/gopacket"
|
||||||
"github.com/google/gopacket/layers"
|
"github.com/google/gopacket/layers"
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package subcommands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -8,7 +8,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"bedrocktool/cmd/bedrocktool/utils"
|
"github.com/bedrock-tool/bedrocktool/utils"
|
||||||
|
|
||||||
"github.com/df-mc/dragonfly/server/world/mcdb"
|
"github.com/df-mc/dragonfly/server/world/mcdb"
|
||||||
"github.com/df-mc/goleveldb/leveldb/opt"
|
"github.com/df-mc/goleveldb/leveldb/opt"
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"bedrocktool/cmd/bedrocktool/utils"
|
"github.com/bedrock-tool/bedrocktool/utils"
|
||||||
|
|
||||||
"github.com/google/subcommands"
|
"github.com/google/subcommands"
|
||||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
|
@ -13,7 +13,7 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"bedrocktool/cmd/bedrocktool/utils"
|
"github.com/bedrock-tool/bedrocktool/utils"
|
||||||
|
|
||||||
"github.com/flytam/filenamify"
|
"github.com/flytam/filenamify"
|
||||||
"github.com/google/subcommands"
|
"github.com/google/subcommands"
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
|
||||||
"bedrocktool/cmd/bedrocktool/utils"
|
"github.com/bedrock-tool/bedrocktool/utils"
|
||||||
|
|
||||||
"github.com/df-mc/dragonfly/server/block"
|
"github.com/df-mc/dragonfly/server/block"
|
||||||
"github.com/df-mc/dragonfly/server/block/cube"
|
"github.com/df-mc/dragonfly/server/block/cube"
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"bedrocktool/cmd/bedrocktool/utils"
|
"github.com/bedrock-tool/bedrocktool/utils"
|
||||||
|
|
||||||
"github.com/df-mc/dragonfly/server/world/chunk"
|
"github.com/df-mc/dragonfly/server/world/chunk"
|
||||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
|
@ -15,7 +15,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"bedrocktool/cmd/bedrocktool/utils"
|
"github.com/bedrock-tool/bedrocktool/utils"
|
||||||
|
|
||||||
"github.com/df-mc/dragonfly/server/block/cube"
|
"github.com/df-mc/dragonfly/server/block/cube"
|
||||||
"github.com/df-mc/dragonfly/server/world"
|
"github.com/df-mc/dragonfly/server/world"
|
|
@ -0,0 +1,281 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/zip"
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"crypto/aes"
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/flytam/filenamify"
|
||||||
|
"github.com/google/subcommands"
|
||||||
|
"github.com/sandertv/gophertunnel/minecraft"
|
||||||
|
"github.com/sandertv/gophertunnel/minecraft/resource"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const KEYS_FILE = "keys.db"
|
||||||
|
|
||||||
|
// decrypt using cfb with segmentsize = 1
|
||||||
|
func cfb_decrypt(data []byte, key []byte) ([]byte, error) {
|
||||||
|
cipher, err := aes.NewCipher([]byte(key))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
shift_register := append(key[:16], data...)
|
||||||
|
iv := make([]byte, 16)
|
||||||
|
off := 0
|
||||||
|
for ; off < len(data); off += 1 {
|
||||||
|
cipher.Encrypt(iv, shift_register)
|
||||||
|
data[off] ^= iv[0]
|
||||||
|
shift_register = shift_register[1:]
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type content_item struct {
|
||||||
|
Path string `json:"path"`
|
||||||
|
Key string `json:"key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Content struct {
|
||||||
|
Content []content_item `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Pack struct {
|
||||||
|
resource.Pack
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Pack) ReadAll() ([]byte, error) {
|
||||||
|
buf := make([]byte, p.Len())
|
||||||
|
off := 0
|
||||||
|
for {
|
||||||
|
n, err := p.ReadAt(buf[off:], int64(off))
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
off += n
|
||||||
|
}
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Pack) Decrypt() ([]byte, error) {
|
||||||
|
data, err := p.ReadAll()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
z, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
zip_out_buf := bytes.NewBuffer(nil)
|
||||||
|
zw := zip.NewWriter(zip_out_buf)
|
||||||
|
|
||||||
|
written := make(map[string]interface{})
|
||||||
|
|
||||||
|
// read key contents file
|
||||||
|
var content Content = Content{}
|
||||||
|
{
|
||||||
|
ff, err := z.Open("contents.json")
|
||||||
|
if err != nil {
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fw, _ := zw.Create("contents.json")
|
||||||
|
buf, _ := io.ReadAll(ff)
|
||||||
|
if err := json.Unmarshal(buf, &content); err != nil {
|
||||||
|
dec, _ := cfb_decrypt(buf[0x100:], []byte(p.ContentKey()))
|
||||||
|
dec = bytes.Split(dec, []byte("\x00"))[0]
|
||||||
|
fw.Write(dec)
|
||||||
|
if err := json.Unmarshal(dec, &content); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fw.Write(buf)
|
||||||
|
}
|
||||||
|
written["contents.json"] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrypt each file in the contents file
|
||||||
|
for _, entry := range content.Content {
|
||||||
|
ff, _ := z.Open(entry.Path)
|
||||||
|
stat, _ := ff.Stat()
|
||||||
|
if ff == nil || stat.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
buf, _ := io.ReadAll(ff)
|
||||||
|
if entry.Key != "" {
|
||||||
|
buf, _ = cfb_decrypt(buf, []byte(entry.Key))
|
||||||
|
}
|
||||||
|
fw, _ := zw.Create(entry.Path)
|
||||||
|
fw.Write(buf)
|
||||||
|
written[entry.Path] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy files not in the contents file
|
||||||
|
for _, src_file := range z.File {
|
||||||
|
if written[src_file.Name] == nil {
|
||||||
|
zw.Copy(src_file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zw.Close()
|
||||||
|
return zip_out_buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dump_keys(keys map[string]string) {
|
||||||
|
f, err := os.OpenFile(KEYS_FILE, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0o775)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
data, err := io.ReadAll(f)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
lines := strings.Split(strings.ReplaceAll(string(data), "\r\n", "\n"), "\n")
|
||||||
|
existing_keys := map[string]string{}
|
||||||
|
for _, v := range lines {
|
||||||
|
if len(v) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
item := strings.Split(v, "=")
|
||||||
|
existing_keys[item[0]] = item[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
for uuid, key := range keys {
|
||||||
|
if key == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
existing := existing_keys[uuid]
|
||||||
|
if existing != "" {
|
||||||
|
logrus.Warnf("key %s exists already\n", uuid)
|
||||||
|
if existing != key {
|
||||||
|
logrus.Warnf("uuid:%s, key in db: %s != new key %s\n", uuid, existing, key)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
f.WriteString(uuid + "=" + key + "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResourcePackCMD struct {
|
||||||
|
server_address string
|
||||||
|
save_encrypted bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ResourcePackCMD) Name() string { return "packs" }
|
||||||
|
func (*ResourcePackCMD) Synopsis() string { return "download resource packs from a server" }
|
||||||
|
|
||||||
|
func (c *ResourcePackCMD) SetFlags(f *flag.FlagSet) {
|
||||||
|
f.StringVar(&c.server_address, "address", "", "remote server address")
|
||||||
|
f.BoolVar(&c.save_encrypted, "save-encrypted", false, "save encrypted resourcepacks")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ResourcePackCMD) Usage() string {
|
||||||
|
return c.Name() + ": " + c.Synopsis() + "\n" + SERVER_ADDRESS_HELP
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ResourcePackCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
|
||||||
|
address, hostname, err := ServerInput(c.server_address)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprint(os.Stderr, err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
serverConn, err := ConnectServer(ctx, address, nil, true, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprint(os.Stderr, err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
serverConn.Close()
|
||||||
|
logrus.Info("Received")
|
||||||
|
|
||||||
|
if len(serverConn.ResourcePacks()) > 0 {
|
||||||
|
logrus.Info("Decrypting Resource Packs")
|
||||||
|
dir := "packs/" + hostname
|
||||||
|
os.MkdirAll(dir, 0o777)
|
||||||
|
|
||||||
|
pack_names := make(map[string]int)
|
||||||
|
for _, pack := range serverConn.ResourcePacks() {
|
||||||
|
pack_names[pack.Name()] += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// dump keys, download and decrypt the packs
|
||||||
|
keys := make(map[string]string)
|
||||||
|
for _, pack := range serverConn.ResourcePacks() {
|
||||||
|
pack := &Pack{*pack}
|
||||||
|
keys[pack.UUID()] = pack.ContentKey()
|
||||||
|
|
||||||
|
pack_name := pack.Name()
|
||||||
|
if pack_names[pack_name] >= 2 {
|
||||||
|
pack_name += "_" + pack.UUID()
|
||||||
|
}
|
||||||
|
pack_name, _ = filenamify.FilenamifyV2(pack_name)
|
||||||
|
|
||||||
|
logrus.Infof("ResourcePack(Id: %s Key: %s | Name: %s %s)\n", pack.UUID(), keys[pack.UUID()], pack_name, pack.Version())
|
||||||
|
|
||||||
|
if c.save_encrypted {
|
||||||
|
data, err := pack.ReadAll()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprint(os.Stderr, err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
os.WriteFile(path.Join(dir, pack_name+".zip"), data, 0o644)
|
||||||
|
}
|
||||||
|
logrus.Infof("Decrypting...")
|
||||||
|
|
||||||
|
data, err := pack.Decrypt()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprint(os.Stderr, err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
os.WriteFile(path.Join(dir, pack_name+".mcpack"), data, 0o644)
|
||||||
|
}
|
||||||
|
logrus.Infof("Writing keys to %s", KEYS_FILE)
|
||||||
|
dump_keys(keys)
|
||||||
|
} else {
|
||||||
|
logrus.Warn("No Resourcepack sent")
|
||||||
|
}
|
||||||
|
fmt.Printf("Done!\n")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterCommand(&ResourcePackCMD{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPacks(server *minecraft.Conn) (packs map[string]*resource.Pack, err error) {
|
||||||
|
packs = make(map[string]*resource.Pack)
|
||||||
|
for _, pack := range server.ResourcePacks() {
|
||||||
|
_pack := &Pack{*pack}
|
||||||
|
if _pack.Encrypted() {
|
||||||
|
data, err := _pack.Decrypt()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pack2, err := resource.FromBytes(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
packs[pack.Name()] = pack2
|
||||||
|
} else {
|
||||||
|
packs[pack.Name()] = pack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
Loading…
Reference in New Issue