Browse Source

Reworked IntAsar Engine, should be functional now

Tim Schuster 1 year ago
parent
commit
d5672beedc
Signed by: Tim Schuster <mail@timschuster.info> GPG Key ID: F9E27097EFB77F61

+ 3
- 3
README.md View File

@@ -5,9 +5,9 @@ modding surface in the client and offloading as much as possible into external c
5 5
 
6 6
 ## Installation
7 7
 
8
-Atm there is no stable node.js-free installer, only an experimental one.
8
+Currently, Discord.Mods uses the node.js ASAR utility to install by default, however, a node.js free binary is available that should be stable and functional.
9 9
 
10
-To install, simply compile the binary with Go of atleast version 1.8.
10
+To install, simply compile the binary with Go of atleast version 1.8 or download the latest release binary from the Releases Page
11 11
 
12 12
 Running the binary is simple;
13 13
 
@@ -20,7 +20,7 @@ The installer will attempt to autodetect most configurations and install itself.
20 20
 By default it uses the external ASAR engine, for this to work you need to have node.js with
21 21
 a compatible `asar` binary in your path. If you do not, the installation will fail safely.
22 22
 
23
-To use the internal engine use `--ext-asar=false`
23
+To use the internal engine use `--ext-asar=false`.
24 24
 
25 25
 ### Installing ASAR
26 26
 

+ 0
- 105
installer/diffasar.go View File

@@ -1,105 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"fmt"
5
-	"github.com/GeertJohan/go.rice"
6
-	"github.com/chzyer/readline"
7
-	"github.com/monmohan/xferspdy"
8
-	"github.com/pkg/errors"
9
-	"golang.org/x/crypto/blake2b"
10
-	"gopkg.in/vmihailenco/msgpack.v2"
11
-	"io"
12
-	"io/ioutil"
13
-	"os"
14
-)
15
-
16
-type diffStruct struct {
17
-	Checksum []byte
18
-	Diff     []xferspdy.Block
19
-}
20
-
21
-func runDiffAsar(path, diff string) error {
22
-	fmt.Println(`
23
-
24
-	You are using the binary-diff ASAR engine,
25
-	this requires you to have an *exact* version of app.asar
26
-
27
-	The engine will fail with an error if this is not the case.
28
-
29
-	`)
30
-	box := rice.MustFindBox("assets")
31
-	var diffData = diffStruct{}
32
-	diffRaw := box.MustBytes("app.asar.diff")
33
-	err := msgpack.Unmarshal(diffRaw, &diffData)
34
-	if err != nil {
35
-		return errors.Wrap(err, "Could not unpack diff file")
36
-	}
37
-	// Todo
38
-	return nil
39
-}
40
-
41
-func makeDiffAsar(path, diff string) error {
42
-	fmt.Println(`
43
-
44
-	This will generate a binary diff from a app.asar.old
45
-	and the installed app.asar.
46
-
47
-	THIS MODE REQUIRES A INTALLED D.MOD bootstrap.js!!!
48
-
49
-	Ensure the following is present in the **CURRENT** folder:
50
-
51
-		- app.asar with bootstrap.js patch
52
-		- app.asar.old from the original app.asar
53
-
54
-	`)
55
-
56
-	prompt, err := readline.Line("Continue? (Y)es/(n)o: ")
57
-	if err != nil {
58
-		return errors.Wrap(err, "Could not read from Console")
59
-	}
60
-	if prompt != "Y" {
61
-		return errors.New("Did not press Y, aborting")
62
-	}
63
-
64
-	fingerprint := xferspdy.NewFingerprint("./app.asar.old", 4096)
65
-
66
-	binaryDiff := xferspdy.NewDiff("./app.asar", *fingerprint)
67
-
68
-	checksum, err := hashFile("./app.asar")
69
-	if err != nil {
70
-		return errors.Wrap(err, "Could not hash app.asar")
71
-	}
72
-
73
-	diffOut := diffStruct{
74
-		Diff:     binaryDiff,
75
-		Checksum: checksum,
76
-	}
77
-	diffData, err := msgpack.Marshal(diffOut)
78
-	if err != nil {
79
-		return errors.Wrap(err, "Could not marshall diff data")
80
-	}
81
-	err = ioutil.WriteFile("app.asar.diff", diffData, 0666)
82
-	if err != nil {
83
-		return errors.Wrap(err, "Could not write diff")
84
-	}
85
-	return nil
86
-}
87
-
88
-func hashFile(file string) ([]byte, error) {
89
-	hasher, err := blake2b.New512([]byte{})
90
-	if err != nil {
91
-		return nil, errors.Wrap(err, "Could not initialize hasher")
92
-	}
93
-	toHash, err := os.Open(file)
94
-	if err != nil {
95
-		return nil, errors.Wrap(err, "Could not open file")
96
-	}
97
-	defer toHash.Close()
98
-
99
-	_, err = io.Copy(hasher, toHash)
100
-	if err != nil {
101
-		return nil, errors.Wrap(err, "Could not hash file")
102
-	}
103
-
104
-	return hasher.Sum(nil), nil
105
-}

+ 1
- 1
installer/extasar.go View File

@@ -17,7 +17,7 @@ func runExtAsar(path, bootstrapper string) error {
17 17
 
18 18
 	`)
19 19
 
20
-	tmp, err := unpackAsar(getResourcePath(path))
20
+	tmp, err := unpackAsar(filepath.Join(getResourcePath(path), "app.asar"))
21 21
 	if err != nil {
22 22
 		return errors.Wrap(err, "Unpacking failed")
23 23
 	}

+ 6
- 6
installer/install.go View File

@@ -20,7 +20,7 @@ var defaultDiscordPaths = []string{
20 20
 	"./discord",
21 21
 }
22 22
 
23
-var resourcePath = []string{"resources", "app.asar"}
23
+var resourcePath = []string{"resources"}
24 24
 
25 25
 const (
26 26
 	lookFor = "global.mainWindowId = mainWindow.id;"
@@ -165,19 +165,19 @@ func main() {
165 165
 `
166 166
 
167 167
 	if !hasBackupFile || *flagKillBackup {
168
-		err = copyFile("app.asar.old", getResourcePath(path))
168
+		err = copyFile("app.asar.old", filepath.Join(getResourcePath(path), "app.asar"))
169 169
 		if err != nil {
170 170
 			fmt.Printf("Could not backup old ASAR: %s\n", err)
171
-			fmt.Printf(failBanner, getResourcePath(path))
171
+			fmt.Printf(failBanner, filepath.Join(getResourcePath(path), "app.asar"))
172 172
 			return
173 173
 		}
174 174
 	} else {
175 175
 		fmt.Println("There already is a backup file, not making a new one...")
176 176
 	}
177
-	err = copyFile(getResourcePath(path), "output.asar")
177
+	err = copyFile(filepath.Join(getResourcePath(path), "app.asar"), "output.asar")
178 178
 	if err != nil {
179 179
 		fmt.Printf("Could not replace with new ASAR: %s\n", err)
180
-		fmt.Printf(failBanner, getResourcePath(path))
180
+		fmt.Printf(failBanner, filepath.Join(getResourcePath(path), "app.asar"))
181 181
 		return
182 182
 	}
183 183
 
@@ -249,7 +249,7 @@ func copyFile(dst, org string) error {
249 249
 		fmt.Println(">> PLEASE CHECK IF THE FILE IS CORRUPTED <<")
250 250
 		return errors.Wrap(err, "Truncate failed, File is corrupted")
251 251
 	}
252
-	_, err = dest.Seek(0, os.SEEK_SET)
252
+	_, err = dest.Seek(0, io.SeekStart)
253 253
 	if err != nil {
254 254
 		return errors.Wrap(err, "Could not seek start of file")
255 255
 	}

+ 34
- 63
installer/intasar.go View File

@@ -1,11 +1,12 @@
1 1
 package main
2 2
 
3 3
 import (
4
-	"bytes"
5 4
 	"fmt"
6 5
 	"github.com/pkg/errors"
6
+	"io/ioutil"
7 7
 	"layeh.com/asar"
8 8
 	"os"
9
+	"path/filepath"
9 10
 	"strings"
10 11
 )
11 12
 
@@ -18,83 +19,53 @@ func runIntAsar(path, bootstrapper string) error {
18 19
 
19 20
 	`)
20 21
 
21
-	file, err := os.Open(getResourcePath(path))
22
-	if err != nil {
23
-		return errors.Wrap(err, "Could not open ASAR")
22
+	if err := unpackAsarInt(path, getResourcePath(path)); err != nil {
23
+		return errors.Wrap(err, "Could not unpack ASAR")
24 24
 	}
25
-	defer file.Close()
26 25
 
27
-	discordAsar, err := asar.Decode(file)
28
-	if err != nil {
29
-		return errors.Wrap(err, "Could not decode ASAR")
30
-	}
26
+	indexJsPath := filepath.Join(getResourcePath(path), "index.js")
31 27
 
32
-	fmt.Println("Beginning install...")
33
-	for k := range discordAsar.Children {
34
-		file := discordAsar.Children[k]
35
-		if file.Path() == "index.js" {
36
-			oldIndexJsStr := file.String()
37
-			oldIndexJsStr, err = uninstall(oldIndexJsStr)
38
-			if err != nil {
39
-				return errors.Wrap(err, "Could not uninstall bootstrap.js")
40
-			}
41
-			newIndexJs, err := install(oldIndexJsStr, bootstrapper)
42
-			if err != nil {
43
-				return errors.Wrap(err, "Could not install bootstrap.js")
44
-			}
45
-			newEntry := asar.New("index.js", bytes.NewReader([]byte(newIndexJs)), int64(len(newIndexJs)), 0, file.Flags)
46
-			discordAsar.Children[k] = newEntry
47
-			break
48
-		}
28
+	stat, err := os.Stat(indexJsPath)
29
+	if err != nil {
30
+		return errors.Wrap(err, "COuld not stat index.js")
49 31
 	}
50
-
51
-	outfile, err := os.Create("./output.asar")
32
+	data, err := ioutil.ReadFile(indexJsPath)
52 33
 	if err != nil {
53
-		return errors.Wrap(err, "Output file could not be created")
34
+		return errors.Wrap(err, "Could not read index.js")
54 35
 	}
55
-	defer outfile.Close()
56
-
57
-	builder := &asar.Builder{}
58 36
 
59
-	err = discordAsar.Walk(func(file string, info os.FileInfo, err error) error {
60
-		recBuilder(discordAsar, builder, file, info, nil)
61
-		return nil
62
-	})
37
+	newIndexJs, err := install(string(data), bootstrapper)
63 38
 	if err != nil {
64
-		return errors.Wrap(err, "Could not fully walk ASAR Contents")
39
+		return errors.Wrap(err, "Could not patch index.js")
65 40
 	}
66 41
 
67
-	_, err = builder.Root().EncodeTo(outfile)
68
-	if err != nil {
69
-		return errors.Wrap(err, "Could not encode ASAR")
42
+	if err := ioutil.WriteFile(indexJsPath, []byte(newIndexJs), stat.Mode()); err != nil {
43
+		return errors.Wrap(err, "Could not write index.js")
70 44
 	}
71
-	return nil
72
-}
73 45
 
74
-func recBuilder(entry *asar.Entry, builder *asar.Builder, file string, info os.FileInfo, content *string) {
75
-	fileSegs := strings.Split(file, "/")
76
-	recBuilderR(entry, builder, fileSegs, info, content)
46
+	return nil
77 47
 }
78 48
 
79
-func recBuilderR(entry *asar.Entry, builder *asar.Builder, file []string, info os.FileInfo, content *string) {
80
-	if len(file) == 0 {
81
-		return
49
+func unpackAsarInt(asarPath, target string) error {
50
+	file, err := os.Open(filepath.Join(getResourcePath(asarPath), "app.asar"))
51
+	if err != nil {
52
+		return errors.Wrap(err, "Could not open ASAR")
82 53
 	}
83
-	if len(file) == 1 {
54
+	asarFile, err := asar.Decode(file)
55
+	if err != nil {
56
+		return errors.Wrap(err, "Could not decode ASAR")
57
+	}
58
+	return asarFile.Walk(func(path string, info os.FileInfo, err error) error {
59
+		if err != nil {
60
+			return err
61
+		}
84 62
 		if info.IsDir() {
85
-			builder.AddDir(file[0], asar.Flag(info.Mode()))
86
-			return
87
-		} else {
88
-			var cBytes = []byte{}
89
-			if content != nil {
90
-				cBytes = bytes.NewBufferString(*content).Bytes()
91
-			} else {
92
-				cBytes = entry.Find(file[0]).Bytes()
93
-			}
94
-			builder.Add(file[0], bytes.NewReader(cBytes), int64(len(cBytes)), asar.Flag(info.Mode()))
95
-			return
63
+			return os.MkdirAll(filepath.Join(target, path), info.Mode())
96 64
 		}
97
-	}
98
-	newBuilder := builder.AddDir(file[0], entry.Find(file[0]).Flags)
99
-	recBuilderR(entry.Find(file[0]), newBuilder, file[1:], info, content)
65
+		ent := asarFile.Find(strings.Split(path, "/")...)
66
+		if ent == nil {
67
+			return errors.Errorf("Could not find file %s in ASAR", path)
68
+		}
69
+		return ioutil.WriteFile(filepath.Join(target, path), ent.Bytes(), info.Mode())
70
+	})
100 71
 }

+ 6
- 6
installer/rice-box.go
File diff suppressed because it is too large
View File


+ 1
- 1
vendor/github.com/layeh/asar/decoder.go View File

@@ -52,7 +52,7 @@ func Decode(ra io.ReaderAt) (*Entry, error) {
52 52
 
53 53
 	// read header string
54 54
 	headerSection := io.NewSectionReader(ra, 8+8, int64(headerStringSize))
55
-	baseOffset := 8 + 8 + int64(headerStringSize)
55
+	baseOffset := 8 + int64(headerSize)
56 56
 	baseOffset += baseOffset % 4 // pickle objects are uint32 aligned
57 57
 
58 58
 	root, err := decodeHeader(ra, headerSection, baseOffset)

+ 1
- 0
vendor/layeh.com/asar/encoder.go View File

@@ -36,6 +36,7 @@ func (enc *entryEncoder) Encode(e *Entry) error {
36 36
 				enc.Header.WriteByte(',')
37 37
 			}
38 38
 			if !validFilename(child.Name) {
39
+				print("Panic on ", child.Name)
39 40
 				panic(errHeader)
40 41
 			}
41 42
 			enc.Write(child.Name)

+ 3
- 3
vendor/vendor.json View File

@@ -33,10 +33,10 @@
33 33
 			"revisionTime": "2017-03-31T03:19:02Z"
34 34
 		},
35 35
 		{
36
-			"checksumSHA1": "J+eojDR9zKhCmtL/pj2LnuIsKa8=",
36
+			"checksumSHA1": "cz1/6EQJ0k46x+oY23P19LOVLkY=",
37 37
 			"path": "github.com/layeh/asar",
38
-			"revision": "5e4d0891fe789f2da0c2d5afada3b6a1ede6d64c",
39
-			"revisionTime": "2016-12-24T16:31:00Z"
38
+			"revision": "30a33f414d1f37b5345e203a29967e2bad9535dc",
39
+			"revisionTime": "2017-06-27T01:04:56Z"
40 40
 		},
41 41
 		{
42 42
 			"checksumSHA1": "uxAGkaw3fZEQuJUaMbd26pHzcYw=",