14 Commits
9.1.3 ... 9.2.4

Author SHA1 Message Date
Alessandro Autiero
170a878e79 Merge pull request #69 from Auties00/_onLoggedIn
Release 9.2.2
2024-07-09 22:38:47 +02:00
Alessandro Autiero
a2505011d9 Release 9.2.2 2024-07-09 20:38:01 +02:00
Alessandro Autiero
3e2c2e96b1 Release 9.2.1 2024-07-07 10:17:07 +02:00
Alessandro Autiero
00802ac6da Merge pull request #65 from Auties00/_onLoggedIn
Release 9.2.0
2024-07-06 20:44:33 +02:00
Alessandro Autiero
1d68469297 Merge pull request #64 from Auties00/_onLoggedIn
Port Forwarding documentation
2024-07-06 20:35:08 +02:00
Alessandro Autiero
83878db8c5 Merge pull request #63 from Auties00/_onLoggedIn
Portforwarding documentation
2024-07-06 20:33:57 +02:00
Alessandro Autiero
e3b8d7d182 Release 9.2.0 2024-07-06 18:43:52 +02:00
Alessandro Autiero
45b8629207 Port Forwarding documentation 2024-07-06 18:34:42 +02:00
Alessandro Autiero
2df1b81485 Port Forwarding documentation 2024-07-06 18:33:22 +02:00
Alessandro Autiero
018ccb7f8e Merge pull request #57 from Auties00/_onLoggedIn
9.1.4
2024-06-15 19:57:54 +02:00
Alessandro Autiero
0d64251623 Reversed logging 2024-06-15 18:48:42 +02:00
Alessandro Autiero
47adb572ea Added back logging 2024-06-15 18:40:46 +02:00
Alessandro Autiero
e3a42d6b81 Fixed small bug 2024-06-15 18:23:43 +02:00
Alessandro Autiero
e24f4e97b3 9.1.4 2024-06-15 17:57:17 +02:00
180 changed files with 4144 additions and 3846 deletions

4
backend/README.md Normal file
View File

@@ -0,0 +1,4 @@
# Backend
Fork of LawinV1
Awaiting rewrite in Dart
Use build.bat to generate the executable

View File

@@ -4,6 +4,16 @@ const fs = require("fs");
const path = require("path"); const path = require("path");
const cookieParser = require("cookie-parser"); const cookieParser = require("cookie-parser");
const audit = require('express-requests-logger')
express.use(audit({
request: {
maxBodyLength: 150
},
response: {
maxBodyLength: 150
}
}));
express.use(Express.json()); express.use(Express.json());
express.use(Express.urlencoded({ extended: true })); express.use(Express.urlencoded({ extended: true }));
express.use(Express.static('public')); express.use(Express.static('public'));

View File

View File

@@ -11,6 +11,7 @@
"dependencies": { "dependencies": {
"cookie-parser": "^1.4.6", "cookie-parser": "^1.4.6",
"express": "^4.18.2", "express": "^4.18.2",
"express-requests-logger": "^4.0.0",
"ini": "^2.0.0", "ini": "^2.0.0",
"nexe": "^4.0.0-rc.6", "nexe": "^4.0.0-rc.6",
"path": "^0.12.7", "path": "^0.12.7",
@@ -388,6 +389,23 @@
"node": ">v0.4.12" "node": ">v0.4.12"
} }
}, },
"node_modules/bunyan": {
"version": "1.8.15",
"resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.15.tgz",
"integrity": "sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==",
"engines": [
"node >=0.10.0"
],
"bin": {
"bunyan": "bin/bunyan"
},
"optionalDependencies": {
"dtrace-provider": "~0.8",
"moment": "^2.19.3",
"mv": "~2",
"safe-json-stringify": "~1"
}
},
"node_modules/bytes": { "node_modules/bytes": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@@ -1063,6 +1081,19 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/dtrace-provider": {
"version": "0.8.8",
"resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz",
"integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==",
"hasInstallScript": true,
"optional": true,
"dependencies": {
"nan": "^2.14.0"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/duplexer3": { "node_modules/duplexer3": {
"version": "0.1.5", "version": "0.1.5",
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz",
@@ -1168,6 +1199,16 @@
"node": ">= 0.10.0" "node": ">= 0.10.0"
} }
}, },
"node_modules/express-requests-logger": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/express-requests-logger/-/express-requests-logger-4.0.0.tgz",
"integrity": "sha512-NHQptnDY0fceiTSWLnW0dbJSFlrvbFpCGHmY6LsTMmJLgkyO3x8qAJ+EsryQRMga20YH8Ynt/vnmg23QP07h1Q==",
"dependencies": {
"bunyan": "^1.8.14",
"flat": "^5.0.2",
"lodash": "^4.17.14"
}
},
"node_modules/express/node_modules/cookie": { "node_modules/express/node_modules/cookie": {
"version": "0.5.0", "version": "0.5.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
@@ -1292,6 +1333,14 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/flat": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
"integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
"bin": {
"flat": "cli.js"
}
},
"node_modules/fn.name": { "node_modules/fn.name": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
@@ -1788,6 +1837,11 @@
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
"integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="
}, },
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/log-symbols": { "node_modules/log-symbols": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
@@ -1973,6 +2027,15 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/moment": {
"version": "2.30.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
"optional": true,
"engines": {
"node": "*"
}
},
"node_modules/moo-server": { "node_modules/moo-server": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/moo-server/-/moo-server-1.3.0.tgz", "resolved": "https://registry.npmjs.org/moo-server/-/moo-server-1.3.0.tgz",
@@ -2009,6 +2072,77 @@
"readable-stream": "^3.6.0" "readable-stream": "^3.6.0"
} }
}, },
"node_modules/mv": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz",
"integrity": "sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==",
"optional": true,
"dependencies": {
"mkdirp": "~0.5.1",
"ncp": "~2.0.0",
"rimraf": "~2.4.0"
},
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/mv/node_modules/glob": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz",
"integrity": "sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"optional": true,
"dependencies": {
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "2 || 3",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
}
},
"node_modules/mv/node_modules/mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
"optional": true,
"dependencies": {
"minimist": "^1.2.6"
},
"bin": {
"mkdirp": "bin/cmd.js"
}
},
"node_modules/mv/node_modules/rimraf": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz",
"integrity": "sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"optional": true,
"dependencies": {
"glob": "^6.0.1"
},
"bin": {
"rimraf": "bin.js"
}
},
"node_modules/nan": {
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz",
"integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==",
"optional": true
},
"node_modules/ncp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
"integrity": "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==",
"optional": true,
"bin": {
"ncp": "bin/ncp"
}
},
"node_modules/negotiator": { "node_modules/negotiator": {
"version": "0.6.3", "version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
@@ -2534,6 +2668,12 @@
} }
] ]
}, },
"node_modules/safe-json-stringify": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz",
"integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==",
"optional": true
},
"node_modules/safe-stable-stringify": { "node_modules/safe-stable-stringify": {
"version": "2.4.3", "version": "2.4.3",
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz",
@@ -3405,6 +3545,17 @@
"wrench": "1.3.x" "wrench": "1.3.x"
} }
}, },
"bunyan": {
"version": "1.8.15",
"resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.15.tgz",
"integrity": "sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==",
"requires": {
"dtrace-provider": "~0.8",
"moment": "^2.19.3",
"mv": "~2",
"safe-json-stringify": "~1"
}
},
"bytes": { "bytes": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@@ -3941,6 +4092,15 @@
} }
} }
}, },
"dtrace-provider": {
"version": "0.8.8",
"resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz",
"integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==",
"optional": true,
"requires": {
"nan": "^2.14.0"
}
},
"duplexer3": { "duplexer3": {
"version": "0.1.5", "version": "0.1.5",
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz",
@@ -4038,6 +4198,16 @@
} }
} }
}, },
"express-requests-logger": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/express-requests-logger/-/express-requests-logger-4.0.0.tgz",
"integrity": "sha512-NHQptnDY0fceiTSWLnW0dbJSFlrvbFpCGHmY6LsTMmJLgkyO3x8qAJ+EsryQRMga20YH8Ynt/vnmg23QP07h1Q==",
"requires": {
"bunyan": "^1.8.14",
"flat": "^5.0.2",
"lodash": "^4.17.14"
}
},
"ext-list": { "ext-list": {
"version": "2.2.2", "version": "2.2.2",
"resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz",
@@ -4130,6 +4300,11 @@
"unpipe": "~1.0.0" "unpipe": "~1.0.0"
} }
}, },
"flat": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
"integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ=="
},
"fn.name": { "fn.name": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
@@ -4496,6 +4671,11 @@
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
"integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="
}, },
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"log-symbols": { "log-symbols": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
@@ -4626,6 +4806,12 @@
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
}, },
"moment": {
"version": "2.30.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
"optional": true
},
"moo-server": { "moo-server": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/moo-server/-/moo-server-1.3.0.tgz", "resolved": "https://registry.npmjs.org/moo-server/-/moo-server-1.3.0.tgz",
@@ -4645,6 +4831,62 @@
"readable-stream": "^3.6.0" "readable-stream": "^3.6.0"
} }
}, },
"mv": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz",
"integrity": "sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==",
"optional": true,
"requires": {
"mkdirp": "~0.5.1",
"ncp": "~2.0.0",
"rimraf": "~2.4.0"
},
"dependencies": {
"glob": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz",
"integrity": "sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==",
"optional": true,
"requires": {
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "2 || 3",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
"optional": true,
"requires": {
"minimist": "^1.2.6"
}
},
"rimraf": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz",
"integrity": "sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==",
"optional": true,
"requires": {
"glob": "^6.0.1"
}
}
}
},
"nan": {
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz",
"integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==",
"optional": true
},
"ncp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
"integrity": "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==",
"optional": true
},
"negotiator": { "negotiator": {
"version": "0.6.3", "version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
@@ -5000,6 +5242,12 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
}, },
"safe-json-stringify": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz",
"integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==",
"optional": true
},
"safe-stable-stringify": { "safe-stable-stringify": {
"version": "2.4.3", "version": "2.4.3",
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz",

View File

@@ -12,7 +12,8 @@
"uuid": "^8.3.2", "uuid": "^8.3.2",
"ws": "^8.5.0", "ws": "^8.5.0",
"xml-parser": "^1.2.1", "xml-parser": "^1.2.1",
"xmlbuilder": "^15.1.1" "xmlbuilder": "^15.1.1",
"express-requests-logger": "^4.0.0"
}, },
"scripts": { "scripts": {
"start": "node index.js", "start": "node index.js",

File diff suppressed because it is too large Load Diff

View File

View File

View File

View File

View File

View File

View File

View File

@@ -75,5 +75,12 @@
"direction": "OUTBOUND", "direction": "OUTBOUND",
"created": "2024-05-31T19:50:04.738Z", "created": "2024-05-31T19:50:04.738Z",
"favorite": false "favorite": false
},
{
"accountId": "Player724",
"status": "ACCEPTED",
"direction": "OUTBOUND",
"created": "2024-06-24T20:15:48.062Z",
"favorite": false
} }
] ]

View File

@@ -98,6 +98,15 @@
"note": "", "note": "",
"favorite": false, "favorite": false,
"created": "2024-05-31T19:50:04.738Z" "created": "2024-05-31T19:50:04.738Z"
},
{
"accountId": "Player724",
"groups": [],
"mutual": 0,
"alias": "",
"note": "",
"favorite": false,
"created": "2024-06-24T20:15:48.062Z"
} }
], ],
"incoming": [], "incoming": [],

View File

@@ -51,7 +51,7 @@ void main(List<String> args) async {
} }
stdout.writeln("Launching game..."); stdout.writeln("Launching game...");
var executable = version.gameExecutable; var executable = version.shippingExecutable;
if(executable == null){ if(executable == null){
throw Exception("Missing game executable at: ${version.location.path}"); throw Exception("Missing game executable at: ${version.location.path}");
} }

View File

@@ -12,7 +12,7 @@ Future<void> startGame() async {
await _startLauncherProcess(version); await _startLauncherProcess(version);
await _startEacProcess(version); await _startEacProcess(version);
var executable = await version.gameExecutable; var executable = await version.shippingExecutable;
if (executable == null) { if (executable == null) {
throw Exception("${version.location.path} no longer contains a Fortnite executable, did you delete or move it?"); throw Exception("${version.location.path} no longer contains a Fortnite executable, did you delete or move it?");
} }

View File

@@ -7,7 +7,7 @@ Future<bool> startServerCli(String? host, int? port, ServerType type) async {
stdout.writeln("Starting backend server..."); stdout.writeln("Starting backend server...");
switch(type){ switch(type){
case ServerType.local: case ServerType.local:
var result = await pingBackend(host ?? kDefaultBackendHost, port ?? kDefaultBackendPort); final result = await pingBackend(host ?? kDefaultBackendHost, port ?? kDefaultBackendPort);
if(result == null){ if(result == null){
throw Exception("Local backend server is not running"); throw Exception("Local backend server is not running");
} }

View File

@@ -10,6 +10,7 @@ export 'package:reboot_common/src/model/server_result.dart';
export 'package:reboot_common/src/model/server_type.dart'; export 'package:reboot_common/src/model/server_type.dart';
export 'package:reboot_common/src/model/update_status.dart'; export 'package:reboot_common/src/model/update_status.dart';
export 'package:reboot_common/src/model/update_timer.dart'; export 'package:reboot_common/src/model/update_timer.dart';
export 'package:reboot_common/src/model/fortnite_server.dart';
export 'package:reboot_common/src/model/dll.dart'; export 'package:reboot_common/src/model/dll.dart';
export 'package:reboot_common/src/util/backend.dart'; export 'package:reboot_common/src/util/backend.dart';
export 'package:reboot_common/src/util/build.dart'; export 'package:reboot_common/src/util/build.dart';
@@ -18,3 +19,4 @@ export 'package:reboot_common/src/util/network.dart';
export 'package:reboot_common/src/util/patcher.dart'; export 'package:reboot_common/src/util/patcher.dart';
export 'package:reboot_common/src/util/path.dart'; export 'package:reboot_common/src/util/path.dart';
export 'package:reboot_common/src/util/process.dart'; export 'package:reboot_common/src/util/process.dart';
export 'package:reboot_common/src/util/log.dart';

View File

@@ -1,2 +1,3 @@
const String kDefaultBackendHost = "127.0.0.1"; const String kDefaultBackendHost = "127.0.0.1";
const int kDefaultBackendPort = 3551; const int kDefaultBackendPort = 3551;
const int kDefaultXmppPort = 80;

View File

@@ -5,7 +5,9 @@ import 'package:path/path.dart' as path;
import 'package:reboot_common/common.dart'; import 'package:reboot_common/common.dart';
extension FortniteVersionExtension on FortniteVersion { extension FortniteVersionExtension on FortniteVersion {
static File? findExecutable(Directory directory, String name) { static String _marker = "FortniteClient.mod";
static File? findFile(Directory directory, String name) {
try{ try{
final result = directory.listSync(recursive: true) final result = directory.listSync(recursive: true)
.firstWhere((element) => path.basename(element.path) == name); .firstWhere((element) => path.basename(element.path) == name);
@@ -15,28 +17,25 @@ extension FortniteVersionExtension on FortniteVersion {
} }
} }
File? get gameExecutable => findExecutable(location, "FortniteClient-Win64-Shipping.exe"); Future<File?> get shippingExecutable async {
final result = findFile(location, "FortniteClient-Win64-Shipping.exe");
Future<File?> get headlessGameExecutable async { if(result == null) {
final result = findExecutable(location, "FortniteClient-Win64-Shipping-Headless.exe");
if(result != null) {
return result;
}
final original = findExecutable(location, "FortniteClient-Win64-Shipping.exe");
if(original == null) {
return null; return null;
} }
final output = File("${original.parent.path}\\FortniteClient-Win64-Shipping-Headless.exe"); final marker = findFile(location, _marker);
await original.copy(output.path); if(marker != null) {
await Isolate.run(() => patchHeadless(output)); return result;
return output;
} }
File? get launcherExecutable => findExecutable(location, "FortniteLauncher.exe"); await Isolate.run(() => patchHeadless(result));
await File("${location.path}\\$_marker").create();
return result;
}
File? get eacExecutable => findExecutable(location, "FortniteClient-Win64-Shipping_EAC.exe"); File? get launcherExecutable => findFile(location, "FortniteLauncher.exe");
File? get splashBitmap => findExecutable(location, "Splash.bmp"); File? get eacExecutable => findFile(location, "FortniteClient-Win64-Shipping_EAC.exe");
File? get splashBitmap => findFile(location, "Splash.bmp");
} }

View File

@@ -1,15 +1,17 @@
import 'dart:io'; import 'dart:io';
import 'dart:isolate'; import 'dart:isolate';
import 'package:version/version.dart';
class FortniteBuild { class FortniteBuild {
final String identifier; final Version version;
final String version;
final String link; final String link;
final bool available;
FortniteBuild({ FortniteBuild({
required this.identifier,
required this.version, required this.version,
required this.link required this.link,
required this.available
}); });
} }

View File

@@ -0,0 +1,47 @@
class FortniteServer {
final String id;
final String name;
final String description;
final String author;
final String ip;
final String version;
final String? password;
final DateTime timestamp;
final bool discoverable;
FortniteServer({
required this.id,
required this.name,
required this.description,
required this.author,
required this.ip,
required this.version,
required this.password,
required this.timestamp,
required this.discoverable
});
factory FortniteServer.fromJson(json) => FortniteServer(
id: json["id"],
name: json["name"],
description: json["description"],
author: json["author"],
ip: json["ip"],
version: json["version"],
password: json["password"],
timestamp: json.containsKey("json") ? DateTime.parse(json["timestamp"]) : DateTime.now(),
discoverable: json["discoverable"] ?? false
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"description": description,
"author": author,
"ip": ip,
"version": version,
"password": password,
"timestamp": timestamp.toString(),
"discoverable": discoverable
};
}

View File

@@ -1,17 +1,22 @@
import 'dart:io'; import 'dart:io';
import 'package:version/version.dart';
class FortniteVersion { class FortniteVersion {
String name; Version content;
Directory location; Directory location;
FortniteVersion.fromJson(json) FortniteVersion.fromJson(json)
: name = json["name"], : content = Version.parse(json["content"]),
location = Directory(json["location"]); location = Directory(json["location"]);
FortniteVersion({required this.name, required this.location}); FortniteVersion({required this.content, required this.location});
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
'name': name, 'content': content.toString(),
'location': location.path 'location': location.path
}; };
@override
bool operator ==(Object other) => other is FortniteVersion && this.content == other.content;
} }

View File

@@ -9,10 +9,11 @@ class GameInstance {
final int? launcherPid; final int? launcherPid;
final int? eacPid; final int? eacPid;
final List<InjectableDll> injectedDlls; final List<InjectableDll> injectedDlls;
bool hosting; final GameServerType? serverType;
bool launched; bool launched;
bool movedToVirtualDesktop; bool movedToVirtualDesktop;
bool tokenError; bool tokenError;
bool killed;
GameInstance? child; GameInstance? child;
GameInstance({ GameInstance({
@@ -20,11 +21,21 @@ class GameInstance {
required this.gamePid, required this.gamePid,
required this.launcherPid, required this.launcherPid,
required this.eacPid, required this.eacPid,
required this.hosting, required this.serverType,
required this.child required this.child
}): tokenError = false, launched = false, movedToVirtualDesktop = false, injectedDlls = []; }): tokenError = false, killed = false, launched = false, movedToVirtualDesktop = false, injectedDlls = [];
void kill() { void kill() {
GameInstance? child = this;
while(child != null) {
child._kill();
child = child.child;
}
}
void _kill() {
launched = true;
killed = true;
Process.killPid(gamePid, ProcessSignal.sigabrt); Process.killPid(gamePid, ProcessSignal.sigabrt);
if(launcherPid != null) { if(launcherPid != null) {
Process.killPid(launcherPid!, ProcessSignal.sigabrt); Process.killPid(launcherPid!, ProcessSignal.sigabrt);
@@ -33,17 +44,10 @@ class GameInstance {
Process.killPid(eacPid!, ProcessSignal.sigabrt); Process.killPid(eacPid!, ProcessSignal.sigabrt);
} }
} }
}
bool get nestedHosting {
GameInstance? child = this; enum GameServerType {
while(child != null) { headless,
if(child.hosting) { virtualWindow,
return true; window
}
child = child.child;
}
return false;
}
} }

View File

@@ -4,6 +4,11 @@ class ServerResult {
final StackTrace? stackTrace; final StackTrace? stackTrace;
ServerResult(this.type, {this.error, this.stackTrace}); ServerResult(this.type, {this.error, this.stackTrace});
@override
String toString() {
return 'ServerResult{type: $type, error: $error, stackTrace: $stackTrace}';
}
} }
enum ServerResultType { enum ServerResultType {

View File

@@ -26,6 +26,7 @@ Future<bool> isBackendPortFree() async => await pingBackend(kDefaultBackendHost,
Future<bool> freeBackendPort() async { Future<bool> freeBackendPort() async {
await killProcessByPort(kDefaultBackendPort); await killProcessByPort(kDefaultBackendPort);
await killProcessByPort(kDefaultXmppPort);
final standardResult = await isBackendPortFree(); final standardResult = await isBackendPortFree();
if(standardResult) { if(standardResult) {
return true; return true;
@@ -35,21 +36,24 @@ Future<bool> freeBackendPort() async {
} }
Future<Uri?> pingBackend(String host, int port, [bool https=false]) async { Future<Uri?> pingBackend(String host, int port, [bool https=false]) async {
var hostName = host.replaceFirst("http://", "").replaceFirst("https://", ""); final hostName = host.replaceFirst("http://", "").replaceFirst("https://", "");
var declaredScheme = host.startsWith("http://") ? "http" : host.startsWith("https://") ? "https" : null; final declaredScheme = host.startsWith("http://") ? "http" : host.startsWith("https://") ? "https" : null;
try{ try{
var uri = Uri( final uri = Uri(
scheme: declaredScheme ?? (https ? "https" : "http"), scheme: declaredScheme ?? (https ? "https" : "http"),
host: hostName, host: hostName,
port: port, port: port,
path: "unknown" path: "unknown"
); );
var client = HttpClient() log("[BACKEND] Pinging $uri...");
..connectionTimeout = const Duration(seconds: 5); final client = HttpClient()
var request = await client.getUrl(uri); ..connectionTimeout = const Duration(seconds: 10);
var response = await request.close(); final request = await client.getUrl(uri);
return response.statusCode == 200 || response.statusCode == 404 ? uri : null; await request.close().timeout(const Duration(seconds: 10));
}catch(_){ log("[BACKEND] Ping successful");
return uri;
}catch(error){
log("[BACKEND] Cannot ping backend: $error");
return https || declaredScheme != null || isLocalHost(host) ? null : await pingBackend(host, port, true); return https || declaredScheme != null || isLocalHost(host) ? null : await pingBackend(host, port, true);
} }
} }
@@ -59,16 +63,16 @@ Stream<String?> watchMatchmakingIp() async* {
return; return;
} }
var observer = matchmakerConfigFile.parent.watch(events: FileSystemEvent.modify); final observer = matchmakerConfigFile.parent.watch(events: FileSystemEvent.modify);
yield* observer.where((event) => event.path == matchmakerConfigFile.path).asyncMap((event) async { yield* observer.where((event) => event.path == matchmakerConfigFile.path).asyncMap((event) async {
try { try {
var config = Config.fromString(await matchmakerConfigFile.readAsString()); final config = Config.fromString(await matchmakerConfigFile.readAsString());
var ip = config.get("GameServer", "ip"); final ip = config.get("GameServer", "ip");
if(ip == null) { if(ip == null) {
return null; return null;
} }
var port = config.get("GameServer", "port"); final port = config.get("GameServer", "port");
if(port == null) { if(port == null) {
return null; return null;
} }
@@ -89,14 +93,14 @@ Stream<String?> watchMatchmakingIp() async* {
} }
Future<void> writeMatchmakingIp(String text) async { Future<void> writeMatchmakingIp(String text) async {
var exists = await matchmakerConfigFile.exists(); final exists = await matchmakerConfigFile.exists();
if(!exists) { if(!exists) {
return; return;
} }
_semaphore.acquire(); _semaphore.acquire();
var splitIndex = text.indexOf(":"); final splitIndex = text.indexOf(":");
var ip = splitIndex != -1 ? text.substring(0, splitIndex) : text; final ip = splitIndex != -1 ? text.substring(0, splitIndex) : text;
var port = splitIndex != -1 ? text.substring(splitIndex + 1) : kDefaultGameServerPort; var port = splitIndex != -1 ? text.substring(splitIndex + 1) : kDefaultGameServerPort;
if(port.isBlank) { if(port.isBlank) {
port = kDefaultGameServerPort; port = kDefaultGameServerPort;
@@ -104,7 +108,7 @@ Future<void> writeMatchmakingIp(String text) async {
_lastIp = ip; _lastIp = ip;
_lastPort = port; _lastPort = port;
var config = Config.fromString(await matchmakerConfigFile.readAsString()); final config = Config.fromString(await matchmakerConfigFile.readAsString());
config.set("GameServer", "ip", ip); config.set("GameServer", "ip", ip);
config.set("GameServer", "port", port); config.set("GameServer", "port", port);
await matchmakerConfigFile.writeAsString(config.toString(), flush: true); await matchmakerConfigFile.writeAsString(config.toString(), flush: true);

View File

@@ -8,6 +8,7 @@ import 'package:dio/io.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:reboot_common/common.dart'; import 'package:reboot_common/common.dart';
import 'package:reboot_common/src/extension/types.dart'; import 'package:reboot_common/src/extension/types.dart';
import 'package:version/version.dart';
const String kStopBuildDownloadSignal = "kill"; const String kStopBuildDownloadSignal = "kill";
@@ -23,7 +24,7 @@ Dio _buildDioInstance() {
return dio; return dio;
} }
final String _archiveSourceUrl = "http://185.203.216.3/versions.json"; final String _archiveSourceUrl = "https://raw.githubusercontent.com/simplyblk/Fortnitebuilds/main/README.md";
final RegExp _rarProgressRegex = RegExp("^((100)|(\\d{1,2}(.\\d*)?))%\$"); final RegExp _rarProgressRegex = RegExp("^((100)|(\\d{1,2}(.\\d*)?))%\$");
const String _deniedConnectionError = "The connection was denied: your firewall might be blocking the download"; const String _deniedConnectionError = "The connection was denied: your firewall might be blocking the download";
const String _unavailableError = "The build downloader is not available right now"; const String _unavailableError = "The build downloader is not available right now";
@@ -41,15 +42,35 @@ Future<List<FortniteBuild>> fetchBuilds(ignored) async {
return []; return [];
} }
final data = jsonDecode(response.data ?? "{}");
var results = <FortniteBuild>[]; var results = <FortniteBuild>[];
for(final entry in data.entries) { for (final line in response.data?.split("\n") ?? []) {
results.add(FortniteBuild( if (!line.startsWith("|")) {
identifier: entry.key, continue;
version: "${entry.value["title"]} (${entry.key})",
link: entry.value["url"]
));
} }
var parts = line.substring(1, line.length - 1).split("|");
if (parts.isEmpty) {
continue;
}
var versionName = parts.first.trim();
final separator = versionName.indexOf("-");
if(separator != -1) {
versionName = versionName.substring(0, separator);
}
final link = parts.last.trim();
try {
results.add(FortniteBuild(
version: Version.parse(versionName),
link: link,
available: link.endsWith(".zip") || link.endsWith(".rar")
));
} on FormatException {
// Ignore
}
}
return results; return results;
} }
@@ -67,7 +88,7 @@ Future<void> downloadArchiveBuild(FortniteBuildDownloadOptions options) async {
} }
final startTime = DateTime.now().millisecondsSinceEpoch; final startTime = DateTime.now().millisecondsSinceEpoch;
final response = _downloadArchive(options, tempFile, startTime); final response = _downloadArchive(options, stopped, tempFile, startTime);
await Future.any([stopped.future, response]); await Future.any([stopped.future, response]);
if(!stopped.isCompleted) { if(!stopped.isCompleted) {
await _extractArchive(stopped, extension, tempFile, options); await _extractArchive(stopped, extension, tempFile, options);
@@ -79,13 +100,17 @@ Future<void> downloadArchiveBuild(FortniteBuildDownloadOptions options) async {
} }
} }
Future<void> _downloadArchive(FortniteBuildDownloadOptions options, File tempFile, int startTime, [int? byteStart = null, int errorsCount = 0]) async { Future<void> _downloadArchive(FortniteBuildDownloadOptions options, Completer stopped, File tempFile, int startTime, [int? byteStart = null, int errorsCount = 0]) async {
var received = byteStart ?? 0; var received = byteStart ?? 0;
try { try {
await _dio.download( await _dio.download(
options.build.link, options.build.link,
tempFile.path, tempFile.path,
onReceiveProgress: (data, length) { onReceiveProgress: (data, length) {
if(stopped.isCompleted) {
throw StateError("Download interrupted");
}
received = data; received = data;
final percentage = (received / length) * 100; final percentage = (received / length) * 100;
_onProgress(startTime, percentage < 1 ? null : DateTime.now().millisecondsSinceEpoch, percentage, false, options); _onProgress(startTime, percentage < 1 ? null : DateTime.now().millisecondsSinceEpoch, percentage, false, options);
@@ -116,12 +141,16 @@ Future<void> _downloadArchive(FortniteBuildDownloadOptions options, File tempFil
) )
); );
}catch(error) { }catch(error) {
if(stopped.isCompleted) {
return;
}
if(errorsCount > _maxErrors || error.toString().contains(_deniedConnectionError) || error.toString().contains(_unavailableError)) { if(errorsCount > _maxErrors || error.toString().contains(_deniedConnectionError) || error.toString().contains(_unavailableError)) {
_onError(error, options); _onError(error, options);
return; return;
} }
await _downloadArchive(options, tempFile, startTime, received, errorsCount + 1); await _downloadArchive(options, stopped, tempFile, startTime, received, errorsCount + 1);
} }
} }
@@ -225,6 +254,7 @@ Future<void> _extractArchive(Completer<dynamic> stopped, String extension, File
} }
await Future.any([stopped.future, process.exitCode]); await Future.any([stopped.future, process.exitCode]);
process.kill(ProcessSignal.sigabrt);
} }
void _onProgress(int startTime, int? now, double percentage, bool extracting, FortniteBuildDownloadOptions options) { void _onProgress(int startTime, int? now, double percentage, bool extracting, FortniteBuildDownloadOptions options) {

View File

@@ -18,7 +18,6 @@ Future<bool> hasRebootDllUpdate(int? lastUpdateMs, {int hours = 24, bool force =
} }
Future<void> downloadCriticalDll(String name, String outputPath) async { Future<void> downloadCriticalDll(String name, String outputPath) async {
print("https://github.com/Auties00/reboot_launcher/raw/master/gui/dependencies/dlls/$name");
final response = await http.get(Uri.parse("https://github.com/Auties00/reboot_launcher/raw/master/gui/dependencies/dlls/$name")); final response = await http.get(Uri.parse("https://github.com/Auties00/reboot_launcher/raw/master/gui/dependencies/dlls/$name"));
if(response.statusCode != 200) { if(response.statusCode != 200) {
throw Exception("Cannot download $name: status code ${response.statusCode}"); throw Exception("Cannot download $name: status code ${response.statusCode}");

View File

@@ -3,7 +3,7 @@ import 'dart:io';
import 'package:reboot_common/common.dart'; import 'package:reboot_common/common.dart';
import 'package:sync/semaphore.dart'; import 'package:sync/semaphore.dart';
final File _loggingFile = _createLoggingFile(); final File launcherLogFile = _createLoggingFile();
final Semaphore _semaphore = Semaphore(1); final Semaphore _semaphore = Semaphore(1);
File _createLoggingFile() { File _createLoggingFile() {
@@ -20,9 +20,9 @@ void log(String message) async {
try { try {
await _semaphore.acquire(); await _semaphore.acquire();
print(message); print(message);
await _loggingFile.writeAsString("$message\n", mode: FileMode.append, flush: true); await launcherLogFile.writeAsString("$message\n", mode: FileMode.append, flush: true);
}catch(error) { }catch(error) {
print(error); print("[LOGGER_ERROR] An error occurred while logging: $error");
}finally { }finally {
_semaphore.release(); _semaphore.release();
} }

View File

@@ -9,6 +9,7 @@ final Uint8List _patchedHeadless = Uint8List.fromList([
45, 0, 108, 0, 111, 0, 103, 0, 32, 0, 45, 0, 110, 0, 111, 0, 115, 0, 112, 0, 108, 0, 97, 0, 115, 0, 104, 0, 32, 0, 45, 0, 110, 0, 111, 0, 115, 0, 111, 0, 117, 0, 110, 0, 100, 0, 32, 0, 45, 0, 110, 0, 117, 0, 108, 0, 108, 0, 114, 0, 104, 0, 105, 0, 32, 0, 45, 0, 117, 0, 115, 0, 101, 0, 111, 0, 108, 0, 100, 0, 105, 0, 116, 0, 101, 0, 109, 0, 99, 0, 97, 0, 114, 0, 100, 0, 115, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0 45, 0, 108, 0, 111, 0, 103, 0, 32, 0, 45, 0, 110, 0, 111, 0, 115, 0, 112, 0, 108, 0, 97, 0, 115, 0, 104, 0, 32, 0, 45, 0, 110, 0, 111, 0, 115, 0, 111, 0, 117, 0, 110, 0, 100, 0, 32, 0, 45, 0, 110, 0, 117, 0, 108, 0, 108, 0, 114, 0, 104, 0, 105, 0, 32, 0, 45, 0, 117, 0, 115, 0, 101, 0, 111, 0, 108, 0, 100, 0, 105, 0, 116, 0, 101, 0, 109, 0, 99, 0, 97, 0, 114, 0, 100, 0, 115, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0
]); ]);
// Not used right now
final Uint8List _originalMatchmaking = Uint8List.fromList([ final Uint8List _originalMatchmaking = Uint8List.fromList([
63, 0, 69, 0, 110, 0, 99, 0, 114, 0, 121, 0, 112, 0, 116, 0, 105, 0, 111, 0, 110, 0, 84, 0, 111, 0, 107, 0, 101, 0, 110, 0, 61 63, 0, 69, 0, 110, 0, 99, 0, 114, 0, 121, 0, 112, 0, 116, 0, 105, 0, 111, 0, 110, 0, 84, 0, 111, 0, 107, 0, 101, 0, 110, 0, 61
]); ]);
@@ -18,7 +19,7 @@ final Uint8List _patchedMatchmaking = Uint8List.fromList([
]); ]);
Future<bool> patchHeadless(File file) async => Future<bool> patchHeadless(File file) async =>
_patch(file, _originalHeadless, _patchedHeadless); await _patch(file, _originalHeadless, _patchedHeadless);
Future<bool> patchMatchmaking(File file) async => Future<bool> patchMatchmaking(File file) async =>
await _patch(file, _originalMatchmaking, _patchedMatchmaking); await _patch(file, _originalMatchmaking, _patchedMatchmaking);
@@ -29,22 +30,24 @@ Future<bool> _patch(File file, Uint8List original, Uint8List patched) async {
throw Exception("Cannot mutate length of binary file"); throw Exception("Cannot mutate length of binary file");
} }
final read = await file.readAsBytes(); final source = await file.readAsBytes();
final length = await file.length();
var readOffset = 0; var readOffset = 0;
var patchOffset = -1; var patchOffset = -1;
var patchCount = 0; var patchCount = 0;
while(readOffset < length){ while(readOffset < source.length){
if(read[readOffset] == original[patchCount]){ if(source[readOffset] == original[patchCount]){
if(patchOffset == -1) { if(patchOffset == -1) {
patchOffset = readOffset; patchOffset = readOffset;
} }
if(++patchCount == original.length) { if(readOffset - patchOffset + 1 == original.length) {
break; break;
} }
patchCount++;
}else { }else {
patchOffset = -1; patchOffset = -1;
patchCount = 0;
} }
readOffset++; readOffset++;
@@ -55,10 +58,10 @@ Future<bool> _patch(File file, Uint8List original, Uint8List patched) async {
} }
for(var i = 0; i < patched.length; i++) { for(var i = 0; i < patched.length; i++) {
read[patchOffset + i] = patched[i]; source[patchOffset + i] = patched[i];
} }
await file.writeAsBytes(read, flush: true); await file.writeAsBytes(source, flush: true);
return true; return true;
}catch(_){ }catch(_){
return false; return false;

Some files were not shown because too many files have changed in this diff Show More