-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
197 lines (166 loc) · 9.61 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
package main
import (
"bytes"
"errors"
"fmt"
"io"
"io/fs"
"log"
"net"
"net/http"
"os"
"path"
"regexp"
"strings"
"github.com/gorilla/mux"
"github.com/jaytaylor/go-hostsfile"
"golang.design/x/hotkey"
)
type Variables struct {
currentDirectory string
capeDirectory string
optifineServerIP string
}
const optifineServer = "s.optifine.net"
func main() {
r := mux.NewRouter()
listener := listen(0)
vars := inits()
// Handling all the requests
r.PathPrefix("/capes/{cape}").HandlerFunc(vars.handleCapes)
r.PathPrefix("/").HandlerFunc(vars.handleOther)
fmt.Printf("Optifine Cape Proxy is listening at %s\n\n", listener.Addr().String())
// Handling the hosts file
handleHostsFile(strings.Replace(listener.Addr().String(), ":80", "", -1))
http.Handle("/", r)
log.Fatal(http.Serve(listener, nil))
}
func inits() Variables {
// Get current working directory and the "capes" folder
currDir, _ := os.Getwd()
capePath := path.Join(currDir, "capes")
// Getting the IP from Optifine Server so that we can use it to forward our requests
resp, _ := http.Post("http://domaintoipconverter.com/index.php", "application/x-www-form-urlencoded", bytes.NewReader([]byte("domains="+optifineServer+"&submit=Convert")))
body, _ := io.ReadAll(resp.Body)
ip := strings.Split(strings.Split(string(body), "<span>")[1], "</span>")[0]
// Check if the "capes" folder is already exists or not
_, err := os.ReadDir(capePath)
if errors.Is(err, fs.ErrNotExist) {
fmt.Println("Put your capes image to \"capes\" directory\nwith format like this \"(username).png\"\n")
exampleCape := []byte{0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x16, 0x08, 0x06, 0x00, 0x00, 0x00, 0xBF, 0x90, 0xAE, 0xF7, 0x00, 0x00, 0x02, 0x42, 0x49, 0x44, 0x41, 0x54, 0x78, 0xDA, 0xB5, 0x97, 0xF9, 0x52, 0x13, 0x41, 0x10, 0xC6, 0xE7, 0x3F, 0xDE, 0x80, 0xB7, 0xF0, 0xE0, 0x4E, 0x38, 0x12, 0x81, 0x80, 0x65, 0x14, 0xB9, 0x0F, 0x51, 0x58, 0xC4, 0xD2, 0x12, 0xC3, 0x15, 0x56, 0x31, 0x80, 0x40, 0x51, 0x16, 0xA5, 0xBE, 0x8D, 0xEF, 0xE3, 0xC3, 0xB4, 0xFD, 0xCD, 0xD2, 0xC3, 0x64, 0x48, 0xC2, 0xCE, 0x50, 0x33, 0x55, 0xBF, 0x9A, 0xDE, 0xE9, 0x9E, 0xCD, 0xB7, 0x9B, 0xAF, 0xA7, 0x12, 0xD5, 0xA5, 0x94, 0xFA, 0xB3, 0x3D, 0x4D, 0x79, 0xD8, 0x79, 0xD1, 0x97, 0x0B, 0xDC, 0x33, 0xCF, 0x68, 0xBE, 0x77, 0x6F, 0x4B, 0xDA, 0x6E, 0xFE, 0xB5, 0x55, 0xA1, 0x18, 0x28, 0x4F, 0xF1, 0xCA, 0x77, 0x5C, 0x6F, 0x4E, 0xD2, 0x75, 0xC2, 0x6C, 0x5A, 0x24, 0xD6, 0x9C, 0x38, 0xF9, 0xA4, 0x0D, 0x4E, 0xDE, 0x57, 0xC7, 0xD9, 0x5A, 0x99, 0x3A, 0x71, 0x67, 0xC3, 0xCF, 0x8D, 0x09, 0x8A, 0x81, 0xAF, 0xF0, 0x93, 0x95, 0x12, 0x01, 0xDB, 0x3E, 0xBF, 0xDF, 0x4F, 0x99, 0x18, 0xB9, 0xA6, 0x0D, 0x57, 0x6F, 0xC7, 0x29, 0x06, 0x2A, 0x60, 0x34, 0x96, 0xC7, 0x3A, 0xDA, 0x0F, 0x79, 0x53, 0x7C, 0xB9, 0xFE, 0x8C, 0x84, 0x7F, 0x7F, 0xEB, 0x1A, 0xF7, 0xDA, 0x5E, 0xCB, 0x4B, 0x88, 0xF0, 0xE3, 0xA5, 0x51, 0x63, 0x35, 0xF9, 0x5C, 0xDB, 0x8E, 0xC8, 0x9B, 0xE2, 0xF3, 0xB5, 0x12, 0x01, 0x14, 0x55, 0xBA, 0xBB, 0x35, 0x88, 0xCF, 0xD9, 0x57, 0xF6, 0x5A, 0x56, 0x57, 0x26, 0xA9, 0xBF, 0xA5, 0xDC, 0x32, 0x0E, 0x11, 0xFE, 0x6D, 0x71, 0x44, 0xDB, 0xCC, 0xD5, 0x22, 0xF6, 0x43, 0xFE, 0xB6, 0x29, 0x56, 0xC7, 0x08, 0xA0, 0xC0, 0x8D, 0xE5, 0xA9, 0x65, 0xDD, 0x87, 0x10, 0xE1, 0xE9, 0xC2, 0x30, 0x5D, 0xBD, 0x1B, 0xD7, 0x9F, 0x89, 0xD9, 0x8D, 0x01, 0x6A, 0xB2, 0xA6, 0x58, 0x1E, 0x25, 0x80, 0x02, 0x37, 0x96, 0x27, 0x97, 0x75, 0x1F, 0x42, 0x84, 0x1F, 0xCD, 0x17, 0x8D, 0x45, 0x6D, 0xBB, 0xDA, 0x16, 0x44, 0x8D, 0x2E, 0xFE, 0xBE, 0x34, 0x42, 0x00, 0x05, 0x6E, 0x6C, 0xAF, 0xF9, 0x12, 0x22, 0xFC, 0x70, 0xB6, 0x40, 0x17, 0x6F, 0x32, 0x8B, 0x62, 0x76, 0x63, 0x80, 0x9A, 0xCC, 0x57, 0xFC, 0xEA, 0x81, 0xF8, 0x49, 0xDE, 0x32, 0xD6, 0x10, 0x4B, 0xDE, 0x97, 0x10, 0xE1, 0x07, 0xAF, 0x87, 0xE8, 0xC7, 0x6A, 0xE9, 0x8E, 0x16, 0xAC, 0x09, 0xA8, 0xC9, 0x7C, 0xC5, 0xAF, 0x3E, 0x9D, 0x2F, 0x10, 0x66, 0x69, 0x88, 0x6C, 0xAD, 0x68, 0xC5, 0x05, 0xB3, 0x96, 0x97, 0xD3, 0x95, 0x30, 0x9F, 0xEF, 0xCF, 0x0C, 0xEA, 0xBD, 0xA2, 0x05, 0xB1, 0xCB, 0x1E, 0xD7, 0xA8, 0xFA, 0xEC, 0x10, 0xC5, 0xA0, 0x11, 0xE8, 0xF3, 0xDD, 0x57, 0x03, 0xD4, 0x60, 0xAB, 0x35, 0xC1, 0xF7, 0x32, 0xF0, 0x35, 0x6A, 0xF8, 0xEB, 0x19, 0xA4, 0x18, 0x1C, 0x2F, 0x86, 0xF9, 0xBC, 0xF6, 0x72, 0x80, 0xF7, 0x0E, 0x1B, 0xC4, 0x32, 0xF6, 0xDA, 0x17, 0xAE, 0x51, 0x7B, 0xAC, 0x3E, 0x06, 0xA1, 0x3E, 0xDF, 0xA9, 0xF6, 0xD3, 0xD7, 0x85, 0xA2, 0xC6, 0x3D, 0xCF, 0x65, 0x1D, 0x35, 0xFC, 0x84, 0xFD, 0x54, 0xE3, 0xC0, 0xCC, 0x55, 0xE7, 0xFA, 0xBE, 0x7C, 0xAB, 0x1C, 0x93, 0xCA, 0xB1, 0xE5, 0x39, 0x3E, 0xF3, 0xCF, 0xE2, 0xA3, 0xB9, 0x82, 0x06, 0x62, 0x31, 0xA7, 0x37, 0x71, 0x7A, 0x13, 0xA3, 0x46, 0xE5, 0xFD, 0x8D, 0xED, 0x4B, 0x5D, 0x8E, 0xAD, 0x80, 0xF1, 0xE9, 0x79, 0xAF, 0xEE, 0x13, 0x88, 0x95, 0x9E, 0xB1, 0x63, 0xE4, 0x55, 0xAC, 0x71, 0x28, 0xC7, 0x56, 0xC0, 0xF8, 0x38, 0xDD, 0x43, 0x07, 0x7C, 0x72, 0x40, 0x2C, 0x66, 0x37, 0x46, 0x3E, 0x9A, 0x70, 0x1C, 0x6B, 0xA1, 0x7B, 0x3F, 0x4C, 0x3D, 0xD5, 0x7D, 0xE2, 0x9E, 0xE7, 0xD2, 0x3F, 0xC8, 0x47, 0x13, 0xBE, 0xCB, 0xBE, 0x7F, 0xC8, 0xFE, 0xED, 0xCA, 0x13, 0xDD, 0x2B, 0xD2, 0x9C, 0x76, 0xFF, 0x20, 0x17, 0x4D, 0x78, 0xAD, 0xDA, 0xF7, 0xA0, 0x9B, 0x6F, 0x4D, 0x3E, 0x6E, 0xDB, 0x3F, 0xC8, 0x45, 0x13, 0xDE, 0xF1, 0x8F, 0x6E, 0xCE, 0x91, 0x4C, 0x3C, 0xA2, 0x76, 0xFC, 0x07, 0x24, 0x63, 0xAD, 0x97, 0x36, 0xB4, 0x68, 0x46, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82}
// Create the "capes" folder
os.Mkdir(capePath, 0777)
// Create an example cape
os.WriteFile(path.Join(capePath, "MrAdhit.png"), exampleCape, 0777)
}
return Variables{
currentDirectory: currDir,
capeDirectory: capePath,
optifineServerIP: ip,
}
}
func handleHostsFile(ip string) {
// Read the hosts file
hostsRaw, _ := hostsfile.ReadHostsFile()
hosts, _ := hostsfile.ParseHosts(hostsfile.ReadHostsFile())
info, _ := os.Stat(hostsfile.HostsPath)
keys := make(map[string]string, 0)
hostsStr := string(hostsRaw)
// Copying the default hosts file so that we can restore it later
defHostsStr := hostsStr
// Remapping the hosts map from [ip : domain] to [domain : ip]
for k, v := range hosts {
for _, s := range v {
keys[s] = k
}
}
// Create the new domain maps
aOptifineSrv := fmt.Sprintf("%s %s", ip, optifineServer)
// Check if there is already other domain maps that uses the Optifine Server domain
if keys[optifineServer] == "" {
// Append the new domain maps to the hosts file
hostsStr = fmt.Sprintf("%s\n%s", hostsStr, aOptifineSrv)
} else {
// Match the other domain maps with Regex
matcher, _ := regexp.Compile("((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4} *" + optifineServer)
// Replace the other domain maps with ours
hostsStr = strings.Replace(hostsStr, matcher.FindString(hostsStr), aOptifineSrv, -1)
defHostsStr = strings.Replace(defHostsStr, matcher.FindString(defHostsStr), "", -1)
}
hasperm := true
// Replacing the hosts file with ours
err := os.WriteFile(hostsfile.HostsPath, []byte(hostsStr), info.Mode())
// Checking if the app has the permission to modify the hosts file
if errors.Is(err, fs.ErrPermission) {
hasperm = false
// Check if our domain maps already in the hosts file so that we don't need to show the warning
if keys[optifineServer] != ip {
// Check if there is already other domain maps, if so told the user to replace it with ours else told the user to add our domain maps
if keys[optifineServer] == "" {
fmt.Printf("Application don't have the permission to modify the hosts file\neither re-run with the appropriate permission or\nmanually add this to the hosts file\n\n %s", aOptifineSrv)
} else {
fmt.Printf("Application don't have the permission to modify the hosts file\neither re-run with the appropriate permission or\nreplace this\n\n %s\n\nto this in the hosts file\n\n %s", keys[optifineServer]+" "+optifineServer, aOptifineSrv)
}
}
}
// Handle the CTRL-C hotkey
go handleHotkeys(defHostsStr, info.Mode(), hasperm)
}
func handleHotkeys(restore string, fmode os.FileMode, hasperm bool) {
// Check if the app has permission so that we can restore the hosts file
if !hasperm {
return
}
// Register the hotkey
fmt.Println("Press CTRL-C to exit\n ")
hk := hotkey.New([]hotkey.Modifier{hotkey.Modifier(0x2)}, hotkey.Key(0x43))
err := hk.Register()
if err != nil {
log.Fatal(err)
}
// Check if the hotkey is pressed, and if so we restore the hosts file
<-hk.Keydown()
fmt.Println("\nRestoring hosts file")
os.WriteFile(hostsfile.HostsPath, []byte(restore), fmode)
os.Exit(0)
}
func listen(iteration uint8) net.Listener {
iteration++
// Try to listen to 127.0.0.1:80
listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.%d:80", iteration))
// If failed try to listen to 127.0.0.2:80 and so on....
if err != nil {
if errors.Is(err, os.ErrPermission) {
log.Fatal(err)
}
return listen(iteration)
}
return listener
}
func (v *Variables) handleCapes(w http.ResponseWriter, r *http.Request) {
// Getting the cape name from the URL path
capeStr := mux.Vars(r)["cape"]
capePath := path.Join(v.capeDirectory, capeStr)
// Check if the cape name contains ".png", if don't, we forward it to the Optifine Server
if !strings.Contains(capeStr, ".png") {
v.handleOther(w, r)
return
}
// Read and Check if the requested cape is exist, if don't, we forward it to the Optifine Server
cape, err := os.ReadFile(capePath)
if errors.Is(err, fs.ErrNotExist) {
v.handleOther(w, r)
return
}
fmt.Printf("Requesting cape \"%s\"\n", capeStr)
w.Write(cape)
}
func (v *Variables) handleOther(w http.ResponseWriter, r *http.Request) {
// Forward other request to the Optifine Server
resp, err := http.Get(fmt.Sprintf("http://%s/%s", v.optifineServerIP, r.URL.Path))
if err != nil {
log.Fatal(err)
}
body, _ := io.ReadAll(resp.Body)
w.Write(body)
}