mirror of
https://github.com/ViaVersion/VIAaaS.git
synced 2024-06-26 10:24:54 +02:00
Compare commits
262 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
5515f507fa | ||
|
e6676c93d9 | ||
|
ee58150767 | ||
|
2462d26b3e | ||
|
48fbe5b3e7 | ||
|
e397893879 | ||
|
07e60e48ce | ||
|
3b0b538a15 | ||
|
cb3de99b9a | ||
|
6371f8ae24 | ||
|
8530d105dd | ||
|
dec53223e4 | ||
|
72d6e4a188 | ||
|
11fc76425f | ||
|
a8ae5ce73d | ||
|
251bc6c39f | ||
|
6587d0d179 | ||
|
39690e2f8d | ||
|
1864dc8194 | ||
|
4007e44568 | ||
|
b88d308eb1 | ||
|
ba15f5459e | ||
|
15e77588c9 | ||
|
89f8295e0a | ||
|
ed24df38a8 | ||
|
989f6b0d22 | ||
|
28d148590f | ||
|
4beb6e46ef | ||
|
8bfebc0ce1 | ||
|
16613dcff9 | ||
|
64ddaf46ae | ||
|
1bba527d49 | ||
|
73fa4d249f | ||
|
4090a6eb12 | ||
|
972a6932b2 | ||
|
6575cf357a | ||
|
39005eb04f | ||
|
d29a2a5ae3 | ||
|
e774f98f2c | ||
|
becd446c77 | ||
|
3fc620fdc2 | ||
|
86809ce227 | ||
|
b16a7ff92d | ||
|
ffbb53c326 | ||
|
e7dedd9aba | ||
|
2be372c19d | ||
|
b9a3467019 | ||
|
15ca031125 | ||
|
1bfa8d41bd | ||
|
0f42f5a76f | ||
|
b99971194d | ||
|
2ea6406db5 | ||
|
937daf986d | ||
|
82e8c2e7c6 | ||
|
61d96086d3 | ||
|
b93105114c | ||
|
d5adabd910 | ||
|
ab64b81f64 | ||
|
5c6197397a | ||
|
94b25c3e5a | ||
|
9312450b69 | ||
|
6bcf746f79 | ||
|
36918fcbb5 | ||
|
9bbee2aa0f | ||
|
e1cd6965a7 | ||
|
55f25914b2 | ||
|
a751c115df | ||
|
2e7faf1ac9 | ||
|
ab7d07a444 | ||
|
7bd7e2bd4f | ||
|
d5931ccb7c | ||
|
f09da91810 | ||
|
bb07aaebb8 | ||
|
ae05cc77c8 | ||
|
dc75958055 | ||
|
f9db7953c1 | ||
|
b1b0bbd5d2 | ||
|
8a1fd9df3a | ||
|
6db0559906 | ||
|
df5f4c67c8 | ||
|
6b406d2a90 | ||
|
fae1f98ec2 | ||
|
acbc0e9948 | ||
|
ef166f3113 | ||
|
64cb615cfe | ||
|
f94637c261 | ||
|
3530d81f28 | ||
|
d2b8f7b617 | ||
|
d407dd2002 | ||
|
1ae643634f | ||
|
0e7ef2034e | ||
|
33d417c089 | ||
|
a2dda5a861 | ||
|
e90529d4aa | ||
|
69ec77b331 | ||
|
776e2fb33c | ||
|
1178c369c2 | ||
|
330b27b3e2 | ||
|
b70daf4a3d | ||
|
743e71157f | ||
|
ec1c5c4d10 | ||
|
8020d9ddec | ||
|
4f87550ee8 | ||
|
64bc013ed3 | ||
|
1ab55c4a09 | ||
|
56239d7ce8 | ||
|
1d1959d86e | ||
|
47ed9ac071 | ||
|
986fbb5a28 | ||
|
3cbacd4f26 | ||
|
2e94870cad | ||
|
81bd833a81 | ||
|
a14adff1fc | ||
|
51727a4e15 | ||
|
7c6a9bbddd | ||
|
469ff8c01d | ||
|
ea5ed29f42 | ||
|
505e5001c8 | ||
|
78d00ce31a | ||
|
f5adcc7a5b | ||
|
2db33465a0 | ||
|
c4d12ae085 | ||
|
b60c7b043d | ||
|
b477194b05 | ||
|
182e2f0591 | ||
|
b653256f07 | ||
|
7fa6e6c888 | ||
|
f7640d9a43 | ||
|
04f64af889 | ||
|
466aee7bc9 | ||
|
d6f21b765a | ||
|
37d23a9708 | ||
|
003b99b010 | ||
|
6cb6063bce | ||
|
253dd58fdc | ||
|
9a99fb4620 | ||
|
9b7821b704 | ||
|
adfa957e66 | ||
|
a6f5197389 | ||
|
ad2b68e9c3 | ||
|
fa3d59c5b0 | ||
|
fe95bd2090 | ||
|
1c9405199c | ||
|
475cc0d1f5 | ||
|
d9920c01ab | ||
|
e6e9432cd1 | ||
|
54ca1dfd27 | ||
|
2bf8b65337 | ||
|
b415fd5223 | ||
|
31c5b13861 | ||
|
1cd928918f | ||
|
7abbb57b76 | ||
|
39f12e1039 | ||
|
7738ae3f4d | ||
|
c7ef8d4481 | ||
|
c6b85a2fd1 | ||
|
03a83dd6da | ||
|
d4628a113a | ||
|
177fa3be22 | ||
|
237761a3d3 | ||
|
fb85cfa329 | ||
|
5a661a3407 | ||
|
9655f8c0ff | ||
|
11ff7db38d | ||
|
b47016626a | ||
|
46f3df5c2e | ||
|
8b71015bc1 | ||
|
a2229d2699 | ||
|
007ff302b9 | ||
|
1244c7b7a0 | ||
|
df33750a40 | ||
|
72f8f00a57 | ||
|
a9ac74e111 | ||
|
062ae5eb53 | ||
|
9b67c1468e | ||
|
49a39eb592 | ||
|
e80c1384c2 | ||
|
2902674638 | ||
|
172e9c2ee5 | ||
|
599538898b | ||
|
8972a03749 | ||
|
c3dbd836c2 | ||
|
eec87f2ef0 | ||
|
9b4bbde742 | ||
|
51befef79d | ||
|
f786444145 | ||
|
9556c7ca31 | ||
|
a0a7f1d76a | ||
|
a1b66b447a | ||
|
7359a48a13 | ||
|
98f8417371 | ||
|
c1846b9a64 | ||
|
7d61e490e5 | ||
|
ebb2f80328 | ||
|
59ee492c1b | ||
|
fd5faeb228 | ||
|
1f05bf04c6 | ||
|
80edc1f4ad | ||
|
862f5085e6 | ||
|
9c2ffb867f | ||
|
cb509383c0 | ||
|
895d558852 | ||
|
fcb6dc42fb | ||
|
3f16486a71 | ||
|
2b2f1b3251 | ||
|
adf0085d8a | ||
|
f5bdc22615 | ||
|
3bd1f0cac4 | ||
|
d636dd09b6 | ||
|
909f707965 | ||
|
4afb3092c2 | ||
|
87e836c6de | ||
|
dce19bcf69 | ||
|
4e0cbf267e | ||
|
aea4f91c6e | ||
|
2c22eab040 | ||
|
6275c48523 | ||
|
2a67ba713a | ||
|
68e790f06c | ||
|
72a166e2be | ||
|
aad148c97e | ||
|
43f09c3130 | ||
|
3c53825d22 | ||
|
907b53a8f5 | ||
|
92c52d5253 | ||
|
f0976df983 | ||
|
822795639a | ||
|
068ac48e59 | ||
|
f22c053b71 | ||
|
886cabafe9 | ||
|
45f380c9dd | ||
|
99226f807e | ||
|
baed1199ec | ||
|
8a6c935730 | ||
|
f66f6ea3dd | ||
|
45fc6e4f40 | ||
|
f09826f3d9 | ||
|
8ecc59ee04 | ||
|
c25745cdc1 | ||
|
171c00a148 | ||
|
396dcb4024 | ||
|
7450d32caf | ||
|
90faa8f854 | ||
|
8e81ae539f | ||
|
f781b76525 | ||
|
0eb1227647 | ||
|
0d5340ace6 | ||
|
47eafd9e5d | ||
|
e9f3a7dc37 | ||
|
f6be0e380b | ||
|
27e3fd6dec | ||
|
61e5b6c863 | ||
|
b93abca795 | ||
|
8e9290fcc9 | ||
|
2fb35f0e2b | ||
|
028ffcc113 | ||
|
4aae403922 | ||
|
3ea5951fd7 | ||
|
f9ae2b4f97 | ||
|
633de5a2e0 | ||
|
9757e76cd6 | ||
|
5fac0e2ae2 |
5
.github/FUNDING.yml
vendored
5
.github/FUNDING.yml
vendored
|
@ -1,5 +1,4 @@
|
|||
custom:
|
||||
- 'https://viaversion.com/donate'
|
||||
- 'https://viaversion.com/backwards'
|
||||
- 'https://viaversion.com/rewind'
|
||||
- 'https://creeper123123321.github.io/#donate'
|
||||
github:
|
||||
- 'creeper123123321'
|
||||
|
|
93
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
93
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
|
@ -0,0 +1,93 @@
|
|||
name: Bug Report
|
||||
description: Report a bug or console error
|
||||
labels: [bug]
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**Before reporting a bug, please see if using latest build fixes your issue.**
|
||||
Whenever you see fit, you can upload images or videos to any of the text fields.
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: "`viaversion dump` Output"
|
||||
description: |
|
||||
Run `viaversion dump` in the console, then copy and paste the given link here.
|
||||
placeholder: |
|
||||
https://dump.viaversion.com/...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Console Error
|
||||
description: |
|
||||
If you encounter warnings/errors in your console, **paste them with https://mclo.gs/ and put the paste link here**.
|
||||
If the error is small/less than 10 lines, you may put it directly into this field.
|
||||
There may be some additional information in ``logs/debug.log``
|
||||
value: |
|
||||
```
|
||||
Put the mclo.gs link or text here.
|
||||
```
|
||||
placeholder: Please do not remove the grave accents; simply replace the line of text in the middle.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Bug Description
|
||||
description: |
|
||||
Describe the unexpected behavior.
|
||||
If you want to attach screenshots, use the comment field at the bottom of the page.
|
||||
placeholder: |
|
||||
Example: "Placing signs on 1.13.2 causes text to disappear."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
description: |
|
||||
List the steps on how we can reproduce the issue. Make sure we can easily understand what you mean with each step.
|
||||
placeholder: |
|
||||
Example:
|
||||
1. Login with a 1.13.2 client
|
||||
2. Place a sign
|
||||
3. The sign text is displayed wrong
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: |
|
||||
Describe what exactly you expected to happen.
|
||||
placeholder: |
|
||||
Example: "Placed sign text should not disappear."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional Server Info
|
||||
description: |
|
||||
Does the backend server use a proxy (eg. BungeeCord)? What software are used and what plugins/mods (Check with F3 debug menu)?
|
||||
placeholder: |
|
||||
Example: "I also use BungeeCord with the following plugins: x, y, z"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Checklist
|
||||
description: Make sure you have followed each of the steps outlined here.
|
||||
options:
|
||||
- label: I have checked if this is specific to VIAaaS platform, and doesn't happen when running it on other platforms (Paper/Sponge/Velocity/Waterfall).
|
||||
required: false
|
||||
- label: I have included a ViaVersion dump.
|
||||
required: true
|
||||
- label: If applicable, I have included a paste (**not a screenshot**) of the error.
|
||||
required: true
|
||||
- label: I have tried the latest build(s) and the issue still persists.
|
||||
required: true
|
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Latest build
|
||||
url: https://github.com/ViaVersion/VIAaaS/actions
|
||||
about: Before reporting a bug, please check if using latest from our ci fixes your issue.
|
||||
- name: ViaVersion Discord
|
||||
url: https://discord.gg/viaversion
|
||||
about: For smaller issues or questions, you can also join our Discord server.
|
38
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
38
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
name: Feature Request
|
||||
description: Suggest a feature to be added
|
||||
labels: [Feature Request]
|
||||
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Problem Description
|
||||
description: |
|
||||
Describe the issue you are facing or why you need the feature to be added.
|
||||
placeholder: |
|
||||
I am always frustrated with...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Solution Description
|
||||
description: |
|
||||
Describe the solution you would like to see.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Alternatives
|
||||
description: |
|
||||
Describe alternatives you have considered.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional Info
|
||||
description: |
|
||||
Does the feature apply to any specific version or environment?
|
||||
validations:
|
||||
required: false
|
11
.github/workflows/dependencyUpdates.yml
vendored
11
.github/workflows/dependencyUpdates.yml
vendored
|
@ -1,11 +0,0 @@
|
|||
name: Gradle dependencyUpdates
|
||||
on: [ push, pull_request ]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 16
|
||||
- run: ./gradlew dependencyUpdates
|
41
.github/workflows/gradle.yml
vendored
41
.github/workflows/gradle.yml
vendored
|
@ -1,23 +1,36 @@
|
|||
# This workflow will build a Java project with Gradle
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
|
||||
name: Gradle build
|
||||
name: CI with Gradle and NPM
|
||||
on: [ push, pull_request ]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v1
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 16
|
||||
- uses: actions/cache@v2
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
check-latest: true
|
||||
- name: Cache Dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.gradle/
|
||||
key: ${{ runner.os }}-build-aspirin-${{ hashFiles('**/build.gradle.kts') }}
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-aspirin-
|
||||
- run: ./gradlew build
|
||||
- uses: actions/upload-artifact@v2
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
name: artifact
|
||||
node-version: 20
|
||||
- name: Install NPM dependencies
|
||||
run: npm ci
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Artifacts
|
||||
path: build/libs/
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,3 +3,4 @@
|
|||
/build
|
||||
/config
|
||||
/logs
|
||||
node_modules/
|
||||
|
|
98
README.md
98
README.md
|
@ -1,18 +1,18 @@
|
|||
VIAaaS
|
||||
---
|
||||
|
||||
[![ViaVersion Discord](https://img.shields.io/badge/chat-on%20discord-blue.svg)](https://viaversion.com/discord)
|
||||
[![Powered by ViaVersion](https://img.shields.io/badge/Powered%20by-ViaVersion-blue.svg)](https://viaversion.com/)
|
||||
|
||||
|
||||
VIAaaS - ViaVersion as a Service - Standalone ViaVersion proxy
|
||||
|
||||
<img alt="VIAaaS Logo (VIA logo with structural formula of aspirin)" height="200" src="https://cdn.discordapp.com/attachments/316218802155028482/850014925622476820/unknown.png">
|
||||
<img alt="VIAaaS Logo (VIA logo with structural formula of aspirin)" height="200" src="https://viaversion.github.io/VIAaaS/src/main/resources/web/img/logo.webp">
|
||||
|
||||
Address generator: https://jo0001.github.io/ViaSetup/aspirin
|
||||
|
||||
Public instances: https://github.com/ViaVersion/VIAaaS/wiki/List-of-Public-Instances
|
||||
|
||||
Discord: https://viaversion.com/discord
|
||||
|
||||
Supported versions: https://viaversion.com/
|
||||
|
||||
## Demo
|
||||
|
||||
Online mode: https://youtu.be/9MKKjuoe66k
|
||||
|
@ -21,18 +21,18 @@ Using with GeyserConnect: https://youtu.be/_LItAIIFmsI
|
|||
|
||||
Using with GeyserConnect on offline mode: https://youtu.be/-hZESD61nSU
|
||||
|
||||
Using with OpenAuthMod: https://youtu.be/h3EfNSxxf8k
|
||||
|
||||
Offline mode tutorial: https://youtu.be/lPdELnrxmp0
|
||||
|
||||
## How does it work?
|
||||
|
||||
- [ViaVersion](https://viaversion.com), [ViaBackwards](https://viaversion.com/backwards)
|
||||
and [ViaRewind](https://viaversion.com/rewind) translates the connections to backend server.
|
||||
- VIAaaS auth page stores account credentials in the player's browser local storage. Check for XSS vulnerabilities on
|
||||
your domain.
|
||||
- It requires a CORS Proxy for calling Mojang APIs, which may make Mojang see that as
|
||||
suspicious and block your account password if the IP address seems suspect.
|
||||
- Account credentials aren't sent to VIAaaS instance, though it's intermediated by CORS Proxy.
|
||||
- The web page receives and validates a the session hash from VIAaaS instance.
|
||||
- VIAaaS auth page stores account credentials in the player's browser local storage.
|
||||
- It requires a CORS Proxy for calling Mojang APIs.
|
||||
- Account credentials aren't sent to VIAaaS instance by default.
|
||||
- The web page receives and validates the joinGame's session hash from VIAaaS instance.
|
||||
|
||||
## Setting up server instance
|
||||
|
||||
|
@ -53,32 +53,22 @@ java -jar VIAaaS-all.jar
|
|||
|
||||
### How to create a public server
|
||||
|
||||
- You need a domain wildcarding to VIAaaS instance, like ``*.example.com -> 192.168.123.123``. You can
|
||||
use [DuckDNS](https://duckdns.org/) DDNS service.
|
||||
- You need a DNS wildcard pointing to VIAaaS instance, like ``*.example.com -> 192.168.123.123``.
|
||||
- Configure the hostname in the config
|
||||
- Open the Minecraft port (25565)
|
||||
- The HTTPS page needs a certificate, you can use [Apache](https://httpd.apache.org/) (with
|
||||
a [Let's Encrypt](https://letsencrypt.org/) certificate) as a reverse proxy. See apache_copypasta.txt file.
|
||||
- The HTTPS page needs a valid SSL certificate, you can use a reverse proxy like [Apache](https://httpd.apache.org/) (with
|
||||
a [Let's Encrypt](https://letsencrypt.org/) certificate).
|
||||
|
||||
## CORS Proxy
|
||||
|
||||
- For less chance of Mojang seeing the login as suspect, you (the player) should set up a CORS proxy on your machine.
|
||||
- Due to Mojang API not allowing cross-origin requests, we need to use a CORS proxy
|
||||
- Note the ending slash in cors-anywhere address
|
||||
- You can also try my public instance at https://crp123-cors.herokuapp.com/ ([source](https://github.com/creeper123123321/cors-anywhere/))
|
||||
|
||||
### Setting up [cors-anywhere](https://www.npmjs.com/package/cors-anywhere) on local machine:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/Rob--W/cors-anywhere
|
||||
cd cors-anywhere
|
||||
npm install
|
||||
node server.js
|
||||
```
|
||||
|
||||
- It will be available at ```http://localhost:8080/```
|
||||
|
||||
## Usage for players
|
||||
|
||||
You'll need to specify which server you want to connect through address parameters
|
||||
added as prefix in ``via.localhost`` or via web page (default https://localhost:25543/).
|
||||
|
||||
#### Offline mode:
|
||||
|
||||
- Connect to ```mc.example.net.via.localhost```
|
||||
|
@ -87,18 +77,22 @@ node server.js
|
|||
|
||||
Web login:
|
||||
|
||||
- You can use the same username for front-end and back-end connection. It's also possible to use an
|
||||
offline mode connection on front-end (use ``_of``).
|
||||
- Go to VIAaaS auth webpage (default is https://localhost:25543/)
|
||||
- Listen to the username A (you'll use it to connect to the VIAaaS instance).
|
||||
- Add the account B (you'll use it in backend server).
|
||||
- Keep the page open
|
||||
- Connect with your account A to ```mc.example.com._u(account B).via.localhost``` (```_u``` can be removed if username is the same)
|
||||
- Connect with your account A to ```mc.example.com._u(account B).via.localhost```
|
||||
- Approve the login in the webpage
|
||||
|
||||
Fabric client:
|
||||
Web login via token caching:
|
||||
|
||||
- Install [ParacetamolAuth](https://github.com/creeper123123321/ParacetamolAuth) in your Fabric client.
|
||||
- Open the web page and save your account in your browser
|
||||
- Send your access token to the instance. After that you can close the page.
|
||||
- Connect to ```mc.example.com.via.localhost``` with the account you sent the token.
|
||||
|
||||
Fabric/Forge client:
|
||||
|
||||
- Install [OpenAuthMod](https://github.com/RaphiMC/OpenAuthMod) in your client.
|
||||
- Join the server: ```mc.example.net.via.localhost```
|
||||
- Approve the login
|
||||
|
||||
|
@ -115,48 +109,44 @@ Fabric client:
|
|||
- You can use ``(option)_(value)`` too, like ``p_25565``.
|
||||
- ```server.example.net```: backend server address
|
||||
- ```_p```: backend port
|
||||
- ```_v```: backend version ([protocol id](https://wiki.vg/Protocol_version_numbers) or name, replace ``.`` with ``_``). ```AUTO``` is default (1.8 fallback).
|
||||
- ```_o```: ```t``` to force online mode in frontend, ```f``` to force offline mode in frontend. If not set, it will be
|
||||
based on backend online mode.
|
||||
- ```_u```: username to use in backend connection
|
||||
- ```_v```: backend version ([protocol id](https://wiki.vg/Protocol_version_numbers) or name, replace ``.`` with ``_``)
|
||||
. ```AUTO``` is default (with 1.8 as fallback).
|
||||
- ```_o```: ```true``` to force online mode in frontend, ```false``` to force offline mode in frontend. If not set, it
|
||||
will be based on backend online mode.
|
||||
- ```_u```: username to use in backend connection (default is front-end username)
|
||||
- ```via.example.com```: instance address (defined in config)
|
||||
|
||||
## WARNING
|
||||
|
||||
- VIAaaS may trigger anti-cheats, due to block, item, movement and other differences between versions. USE AT OWN RISK.
|
||||
- Take care of browser local storage. Check for XSS vulnerabilities on your domain.
|
||||
- Check the security of CORS proxy, it will intermediate Mojang API calls.
|
||||
- Mojang may lock your account when API is called from a suspect IP address.
|
||||
- Check the security of CORS proxy, it will be used for calling to Mojang API.
|
||||
|
||||
## FAQ
|
||||
|
||||
### Accounts
|
||||
|
||||
#### My Microsoft account <18 years old is not able to log in, it's giving XSTS error:
|
||||
|
||||
- Add your account to a family (see https://wiki.vg/Microsoft_Authentication_Scheme#Authenticate_with_XSTS)
|
||||
|
||||
#### Why a online webpage for online mode?:
|
||||
#### Why to use an online webpage for online mode?:
|
||||
|
||||
- It's easier to maintain in that way, because providing login via chat requires encoding and decoding more packets,
|
||||
which reduces maintanability.
|
||||
which reduces maintainability.
|
||||
- It allows your account password and token to be kept with you.
|
||||
|
||||
#### How to use Microsoft Account?:
|
||||
|
||||
- If you are using a public VIAaaS instance, use this page https://viaversion.github.io/VIAaaS/ and configure the
|
||||
WebSocket address.
|
||||
- If you're an administrator of the instance, edit ```config/web/js/config.js``` (default is in the jar) and
|
||||
configure your [Azure Client ID](https://wiki.vg/Microsoft_Authentication_Scheme#Microsoft_OAuth_Flow) and your domain
|
||||
whitelist.
|
||||
|
||||
### Connection
|
||||
|
||||
#### How to use IPv6?:
|
||||
|
||||
- When listening to 0.0.0.0, it should listen on IPv6 too.
|
||||
- The hostname parser currently doesn't support direct IPv6, but you can use a DNS name with https://sslip.io/
|
||||
|
||||
#### I'm getting a DNS error/"Unknown host" while connecting to (...).localhost
|
||||
#### I'm getting a DNS error/"Unknown host" while connecting to via.localhost
|
||||
|
||||
- Try configuring via.localho.st as hostname suffix
|
||||
- Try configuring ```via.localho.st``` as hostname suffix instead
|
||||
|
||||
#### How to use with Geyser?
|
||||
|
||||
|
@ -172,8 +162,12 @@ Fabric client:
|
|||
#### Can I use it to connect to .onion Minecraft hidden servers?
|
||||
|
||||
- You can use .onion addresses if the instance is proxying the backend connections to TOR. Note that VIAaaS may log your
|
||||
requests, and that your DNS queries may be unencrypted.
|
||||
requests, and that your DNS queries may be sent unencrypted.
|
||||
|
||||
#### Can you support more versions / Is there some alternative?
|
||||
|
||||
- See [DirtMultiVersion](https://github.com/DirtPowered/DirtMultiversion) and RK_01's ViaProxy server (lenni0451.net:25563)
|
||||
- See [DirtMultiVersion](https://github.com/DirtPowered/DirtMultiversion) and [ViaProxy](https://github.com/ViaVersion/ViaProxy)
|
||||
|
||||
#### Can I customize the files of HTTP server?
|
||||
|
||||
- Add files to ``config/web/`` directory
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
# command to installing apache + certbot
|
||||
sudo apt install apache2 python3-certbot-apache
|
||||
# generate the let's encrypt certificate with certbot
|
||||
|
||||
# enable some needed modules
|
||||
sudo a2enmod rewrite ssl proxy_http proxy_connect proxy_wstunnel
|
||||
|
||||
# this is a example configuration for using in VirtualHost of Apache config
|
||||
# https://stackoverflow.com/questions/19294816/is-it-possible-to-ignore-an-apache-proxyd-certificate
|
||||
# https://stackoverflow.com/questions/27526281/websockets-and-apache-proxy-how-to-configure-mod-proxy-wstunnel
|
||||
SSLProxyEngine on
|
||||
SSLProxyCheckPeerCN off
|
||||
SSLProxyCheckPeerExpire off
|
||||
ProxyPreserveHost on
|
||||
RewriteEngine on
|
||||
RewriteCond %{HTTP:Upgrade} =websocket [NC]
|
||||
RewriteRule ^/viaaas/(.*) wss://localhost:25543/$1 [P,L]
|
||||
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
|
||||
RewriteRule ^/viaaas/(.*) https://localhost:25543/$1 [P,L]
|
144
build.gradle.kts
144
build.gradle.kts
|
@ -1,3 +1,6 @@
|
|||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer
|
||||
import com.google.javascript.jscomp.CompilerOptions.LanguageMode
|
||||
import com.googlecode.htmlcompressor.compressor.HtmlCompressor
|
||||
import org.gradlewebtools.minify.minifier.js.JsMinifier
|
||||
import org.gradlewebtools.minify.minifier.js.JsMinifierOptions
|
||||
|
@ -6,39 +9,39 @@ import java.nio.file.Files as JFiles
|
|||
|
||||
buildscript {
|
||||
repositories { mavenCentral() }
|
||||
dependencies { classpath("com.github.hazendaz:htmlcompressor:1.7.1") }
|
||||
dependencies { classpath("com.github.hazendaz:htmlcompressor:2.0.0") }
|
||||
}
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
application
|
||||
kotlin("jvm") version "1.5.21"
|
||||
kotlin("jvm") version "1.9.22"
|
||||
id("maven-publish")
|
||||
id("com.github.johnrengelman.shadow") version "7.0.0"
|
||||
id("com.github.ben-manes.versions") version "0.39.0"
|
||||
id("com.palantir.git-version") version "0.12.3"
|
||||
id("org.gradlewebtools.minify") version "1.3.0" apply false
|
||||
id("com.github.ben-manes.versions") version "0.50.0"
|
||||
id("com.github.johnrengelman.shadow") version "8.1.1"
|
||||
id("com.palantir.git-version") version "3.0.0"
|
||||
id("org.gradlewebtools.minify") version "2.1.0" apply false
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass.set("com.viaversion.aas.VIAaaSKt")
|
||||
applicationDefaultJvmArgs = listOf("-Dio.ktor.development=true")
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(11))
|
||||
languageVersion.set(JavaLanguageVersion.of(17))
|
||||
vendor.set(JvmVendorSpec.ADOPTIUM)
|
||||
}
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
val compileKotlin: KotlinCompile by tasks
|
||||
compileKotlin.kotlinOptions.jvmTarget = "11"
|
||||
compileKotlin.kotlinOptions.jvmTarget = "17"
|
||||
|
||||
val gitVersion: groovy.lang.Closure<String> by extra
|
||||
|
||||
group = "com.github.creeper123123321.viaaas"
|
||||
version = "0.4.12+" + try {
|
||||
group = "com.viaversion.aas"
|
||||
version = "0.4.19+" + try {
|
||||
gitVersion()
|
||||
} catch (e: Exception) {
|
||||
"unknown"
|
||||
|
@ -48,55 +51,70 @@ extra.set("archivesBaseName", "VIAaaS")
|
|||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://oss.sonatype.org/content/repositories/snapshots")
|
||||
maven("https://repo.viaversion.com/")
|
||||
maven("https://repo.aikar.co/content/groups/aikar/")
|
||||
maven("https://jitpack.io")
|
||||
maven("https://nexus.velocitypowered.com/repository/maven-public/")
|
||||
mavenLocal()
|
||||
maven("https://repo.papermc.io/repository/maven-public/")
|
||||
maven("https://jitpack.io/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(kotlin("stdlib-jdk8"))
|
||||
implementation(kotlin("reflect"))
|
||||
|
||||
val vvVer = "4.0.2-SNAPSHOT"
|
||||
val vbVer = "4.0.2-SNAPSHOT"
|
||||
val vrVer = "f2d2de0a72"
|
||||
implementation("com.viaversion:viaversion:$vvVer") { isTransitive = false }
|
||||
implementation("com.viaversion:viabackwards:$vbVer") { isTransitive = false }
|
||||
implementation("com.github.ViaVersion.ViaRewind:viarewind-all:$vrVer") { isTransitive = false }
|
||||
val vvVer = "5.0.1-SNAPSHOT"
|
||||
val vbVer = "5.0.1-SNAPSHOT"
|
||||
val vrVer = "4.0.0"
|
||||
implementation("com.viaversion:viaversion-common:$vvVer") { isTransitive = false }
|
||||
implementation("com.viaversion:viabackwards-common:$vbVer") { isTransitive = false }
|
||||
implementation("com.viaversion:viarewind-common:$vrVer") { isTransitive = false }
|
||||
implementation("net.raphimc:ViaAprilFools:3.0.1-SNAPSHOT")
|
||||
implementation("net.raphimc:ViaLegacy:3.0.1-SNAPSHOT")
|
||||
|
||||
implementation("io.netty:netty-all:4.1.67.Final")
|
||||
implementation("io.netty:netty-tcnative-boringssl-static:2.0.40.Final")
|
||||
implementation("io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.8.Final:linux-x86_64")
|
||||
val nettyVer = "4.1.111.Final"
|
||||
implementation("io.netty:netty-handler-proxy:$nettyVer")
|
||||
implementation("io.netty:netty-resolver-dns:$nettyVer")
|
||||
implementation("io.netty:netty-transport-native-epoll:$nettyVer:linux-aarch_64")
|
||||
implementation("io.netty:netty-transport-native-epoll:$nettyVer:linux-x86_64")
|
||||
implementation("io.netty:netty-tcnative-boringssl-static:2.0.65.Final:linux-aarch_64")
|
||||
implementation("io.netty:netty-tcnative-boringssl-static:2.0.65.Final:linux-x86_64")
|
||||
implementation("io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.25.Final:linux-aarch_64")
|
||||
implementation("io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.25.Final:linux-x86_64")
|
||||
|
||||
implementation("com.google.guava:guava:30.1.1-jre")
|
||||
implementation("com.velocitypowered:velocity-native:3.0.0")
|
||||
implementation("net.coobird:thumbnailator:0.4.14")
|
||||
implementation("com.google.guava:guava:33.2.1-jre")
|
||||
implementation("com.velocitypowered:velocity-native:3.3.0-SNAPSHOT")
|
||||
implementation("net.coobird:thumbnailator:0.4.20")
|
||||
implementation("org.powernukkit.fastutil:fastutil-lite:8.1.1")
|
||||
implementation("org.yaml:snakeyaml:1.29")
|
||||
implementation("org.yaml:snakeyaml:2.2")
|
||||
|
||||
val log4jVer = "2.14.1"
|
||||
val slf4jVer = "1.7.32"
|
||||
implementation("net.minecrell:terminalconsoleappender:1.2.0")
|
||||
val log4jVer = "2.23.1"
|
||||
val slf4jVer = "2.0.12"
|
||||
implementation("com.lmax:disruptor:3.4.4")
|
||||
implementation("net.minecrell:terminalconsoleappender:1.3.0")
|
||||
implementation("org.apache.logging.log4j:log4j-core:$log4jVer")
|
||||
implementation("org.apache.logging.log4j:log4j-iostreams:$log4jVer")
|
||||
implementation("org.apache.logging.log4j:log4j-jul:$log4jVer")
|
||||
implementation("org.apache.logging.log4j:log4j-slf4j-impl:$log4jVer")
|
||||
implementation("org.jline:jline-terminal-jansi:3.20.0")
|
||||
implementation("org.apache.logging.log4j:log4j-slf4j2-impl:$log4jVer")
|
||||
implementation("org.jline:jline-terminal-jansi:3.25.1")
|
||||
implementation("org.slf4j:slf4j-api:$slf4jVer")
|
||||
|
||||
val ktorVersion = "1.6.2"
|
||||
implementation("io.ktor:ktor-network-tls-certificates:$ktorVersion")
|
||||
implementation("io.ktor:ktor-websockets:$ktorVersion")
|
||||
implementation("io.ktor:ktor-server-netty:$ktorVersion")
|
||||
implementation("io.ktor:ktor-client-gson:$ktorVersion")
|
||||
implementation("io.ktor:ktor-client-java:$ktorVersion")
|
||||
val ktorVersion = "2.3.11"
|
||||
implementation("io.ktor:ktor-network-tls-certificates-jvm:$ktorVersion")
|
||||
implementation("io.ktor:ktor-server-websockets:$ktorVersion")
|
||||
implementation("io.ktor:ktor-server-netty-jvm:$ktorVersion")
|
||||
implementation("io.ktor:ktor-server-caching-headers:$ktorVersion")
|
||||
implementation("io.ktor:ktor-server-call-logging:$ktorVersion")
|
||||
implementation("io.ktor:ktor-server-compression:$ktorVersion")
|
||||
implementation("io.ktor:ktor-server-config-yaml:$ktorVersion")
|
||||
implementation("io.ktor:ktor-server-content-negotiation:$ktorVersion")
|
||||
implementation("io.ktor:ktor-server-default-headers:$ktorVersion")
|
||||
implementation("io.ktor:ktor-server-forwarded-header:$ktorVersion")
|
||||
implementation("io.ktor:ktor-server-partial-content:$ktorVersion")
|
||||
implementation("io.ktor:ktor-serialization-gson:$ktorVersion")
|
||||
implementation("io.ktor:ktor-client-java-jvm:$ktorVersion")
|
||||
implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
|
||||
implementation("io.ktor:ktor-client-logging-jvm:$ktorVersion")
|
||||
testImplementation("io.ktor:ktor-server-test-host:$ktorVersion")
|
||||
testImplementation("io.ktor:ktor-server-test-host-jvm:$ktorVersion")
|
||||
|
||||
implementation("com.auth0:java-jwt:3.18.1")
|
||||
implementation("com.auth0:java-jwt:4.4.0")
|
||||
}
|
||||
|
||||
val run: JavaExec by tasks
|
||||
|
@ -104,9 +122,9 @@ run.standardInput = System.`in`
|
|||
|
||||
project.configurations.implementation.get().isCanBeResolved = true
|
||||
tasks {
|
||||
named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
|
||||
named<ShadowJar>("shadowJar") {
|
||||
configurations = listOf(project.configurations.implementation.get())
|
||||
transform(com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer::class.java)
|
||||
transform(Log4j2PluginsCacheFileTransformer::class.java)
|
||||
}
|
||||
build {
|
||||
dependsOn(shadowJar)
|
||||
|
@ -117,8 +135,17 @@ tasks {
|
|||
}
|
||||
|
||||
class JsMinifyFilter(reader: java.io.Reader) : java.io.FilterReader("".reader()) {
|
||||
companion object {
|
||||
val minifier = JsMinifier(
|
||||
minifierOptions = JsMinifierOptions(
|
||||
originalFileNames = true,
|
||||
languageOut = LanguageMode.ECMASCRIPT_2020,
|
||||
rewritePolyfills = true
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
init {
|
||||
val minifier = JsMinifier(minifierOptions = JsMinifierOptions(originalFileNames = true))
|
||||
val file = JFiles.createTempDirectory("via-").resolve("tmp-minify.js").toFile().also {
|
||||
it.writeText(reader.readText())
|
||||
}
|
||||
|
@ -142,13 +169,38 @@ tasks.named<ProcessResources>("processResources") {
|
|||
)
|
||||
}
|
||||
filesMatching("**/*.js") {
|
||||
//filter<JsMinifyFilter>()
|
||||
filter<JsMinifyFilter>()
|
||||
}
|
||||
filesMatching("**/*.html") {
|
||||
filter<HtmlMinifyFilter>()
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register<Exec>("compileTs") {
|
||||
group = "build"
|
||||
description = "Compiles TypeScript resources into JS"
|
||||
workingDir = rootProject.rootDir
|
||||
|
||||
onlyIf {
|
||||
val hasNpx = try {
|
||||
val result = exec {
|
||||
isIgnoreExitValue = true
|
||||
commandLine("sh", "-c", "command -v npx")
|
||||
}
|
||||
result.exitValue == 0
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
|
||||
if (!hasNpx) println("Command npx isn't available")
|
||||
return@onlyIf hasNpx
|
||||
}
|
||||
|
||||
commandLine("npx", "tsc")
|
||||
}
|
||||
|
||||
tasks.getByName("processResources").dependsOn("compileTs")
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
|
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,5 +1,7 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
296
gradlew
vendored
296
gradlew
vendored
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -17,67 +17,99 @@
|
|||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MSYS* | MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
@ -87,9 +119,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
@ -98,88 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the
|
|||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
39
gradlew.bat
vendored
39
gradlew.bat
vendored
|
@ -14,7 +14,7 @@
|
|||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
|
@ -25,7 +25,8 @@
|
|||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
|
@ -33,20 +34,20 @@ set APP_HOME=%DIRNAME%
|
|||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
set DEFAULT_JVM_OPTS=-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
|
@ -56,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
|
@ -75,15 +76,17 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
:omega
|
|
@ -1,5 +1,5 @@
|
|||
before_install:
|
||||
- curl -s "https://get.sdkman.io" | bash
|
||||
- source "$HOME/.sdkman/bin/sdkman-init.sh"
|
||||
- sdk install java 16.0.1-open
|
||||
- sdk use java 16.0.1-open
|
||||
- curl -s "https://get.sdkman.io" | bash
|
||||
- source ~/.sdkman/bin/sdkman-init.sh
|
||||
- sdk install java 17.0.10-tem
|
||||
- sdk use java 17.0.10-tem
|
||||
|
|
206
package-lock.json
generated
Normal file
206
package-lock.json
generated
Normal file
|
@ -0,0 +1,206 @@
|
|||
{
|
||||
"name": "viaaas-web",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "viaaas-web",
|
||||
"dependencies": {
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@azure/msal-browser": "^2.27.0",
|
||||
"@types/bootstrap": "^5.1.12",
|
||||
"@types/jquery": "^3.5.14",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"bootstrap": "^5.1.3",
|
||||
"jquery": "^3.6.0",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/msal-browser": {
|
||||
"version": "2.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-2.28.1.tgz",
|
||||
"integrity": "sha512-5uAfwpNGBSRzBGTSS+5l4Zw6msPV7bEmq99n0U3n/N++iTcha+nIp1QujxTPuOLHmTNCeySdMx9qzGqWuy22zQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@azure/msal-common": "^7.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/msal-common": {
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-7.3.0.tgz",
|
||||
"integrity": "sha512-revxB3z+QLjwAtU1d04nC1voFr+i3LfqTpUfgrWZVqKh/sSgg0mZZUvw4vKVWB57qtL95sul06G+TfdFZny1Xw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@popperjs/core": {
|
||||
"version": "2.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
|
||||
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/bootstrap": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/bootstrap/-/bootstrap-5.2.3.tgz",
|
||||
"integrity": "sha512-r2SE9NYaaI7B/jJk8gqRtXzlhgFL6dlXBResJkCbQa8ept619WeiOIO4zBQxdmUFzkKNWLK5ZOyYGI3QZoaqbQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.9.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/jquery": {
|
||||
"version": "3.5.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.14.tgz",
|
||||
"integrity": "sha512-X1gtMRMbziVQkErhTQmSe2jFwwENA/Zr+PprCkF63vFq+Yt5PZ4AlKqgmeNlwgn7dhsXEK888eIW2520EpC+xg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/sizzle": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/sizzle": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz",
|
||||
"integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/uuid": {
|
||||
"version": "8.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
|
||||
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/bootstrap": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.0.tgz",
|
||||
"integrity": "sha512-qlnS9GL6YZE6Wnef46GxGv1UpGGzAwO0aPL1yOjzDIJpeApeMvqV24iL+pjr2kU4dduoBA9fINKWKgMToobx9A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/twbs"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/bootstrap"
|
||||
}
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@popperjs/core": "^2.11.5"
|
||||
}
|
||||
},
|
||||
"node_modules/jquery": {
|
||||
"version": "3.6.1",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz",
|
||||
"integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.4.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
|
||||
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@azure/msal-browser": {
|
||||
"version": "2.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-2.28.1.tgz",
|
||||
"integrity": "sha512-5uAfwpNGBSRzBGTSS+5l4Zw6msPV7bEmq99n0U3n/N++iTcha+nIp1QujxTPuOLHmTNCeySdMx9qzGqWuy22zQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@azure/msal-common": "^7.3.0"
|
||||
}
|
||||
},
|
||||
"@azure/msal-common": {
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-7.3.0.tgz",
|
||||
"integrity": "sha512-revxB3z+QLjwAtU1d04nC1voFr+i3LfqTpUfgrWZVqKh/sSgg0mZZUvw4vKVWB57qtL95sul06G+TfdFZny1Xw==",
|
||||
"dev": true
|
||||
},
|
||||
"@popperjs/core": {
|
||||
"version": "2.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
|
||||
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/bootstrap": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/bootstrap/-/bootstrap-5.2.3.tgz",
|
||||
"integrity": "sha512-r2SE9NYaaI7B/jJk8gqRtXzlhgFL6dlXBResJkCbQa8ept619WeiOIO4zBQxdmUFzkKNWLK5ZOyYGI3QZoaqbQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@popperjs/core": "^2.9.2"
|
||||
}
|
||||
},
|
||||
"@types/jquery": {
|
||||
"version": "3.5.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.14.tgz",
|
||||
"integrity": "sha512-X1gtMRMbziVQkErhTQmSe2jFwwENA/Zr+PprCkF63vFq+Yt5PZ4AlKqgmeNlwgn7dhsXEK888eIW2520EpC+xg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/sizzle": "*"
|
||||
}
|
||||
},
|
||||
"@types/sizzle": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz",
|
||||
"integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/uuid": {
|
||||
"version": "8.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
|
||||
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
|
||||
"dev": true
|
||||
},
|
||||
"bootstrap": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.0.tgz",
|
||||
"integrity": "sha512-qlnS9GL6YZE6Wnef46GxGv1UpGGzAwO0aPL1yOjzDIJpeApeMvqV24iL+pjr2kU4dduoBA9fINKWKgMToobx9A==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"jquery": {
|
||||
"version": "3.6.1",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz",
|
||||
"integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "5.4.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
|
||||
"integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ=="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
20
package.json
Normal file
20
package.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"description": "VIAaaS web resources",
|
||||
"name": "viaaas-web",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@azure/msal-browser": "^2.27.0",
|
||||
"@types/bootstrap": "^5.1.12",
|
||||
"@types/jquery": "^3.5.14",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"bootstrap": "^5.1.3",
|
||||
"jquery": "^3.6.0",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "./gradlew run"
|
||||
},
|
||||
"dependencies": {
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
}
|
3
settings.gradle.kts
Normal file
3
settings.gradle.kts
Normal file
|
@ -0,0 +1,3 @@
|
|||
plugins {
|
||||
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
|
||||
}
|
|
@ -1,15 +1,21 @@
|
|||
package com.viaversion.aas.codec;
|
||||
|
||||
import com.velocitypowered.natives.compression.JavaVelocityCompressor;
|
||||
import com.velocitypowered.natives.compression.VelocityCompressor;
|
||||
import com.velocitypowered.natives.util.MoreByteBufUtils;
|
||||
import com.velocitypowered.natives.util.Natives;
|
||||
import com.viaversion.aas.config.VIAaaSConfig;
|
||||
import com.viaversion.aas.handler.MinecraftHandler;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import io.netty.handler.codec.MessageToMessageCodec;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.zip.DataFormatException;
|
||||
|
||||
public class CompressionCodec extends MessageToMessageCodec<ByteBuf, ByteBuf> {
|
||||
// stolen from Krypton (GPL) and modified
|
||||
|
@ -17,23 +23,60 @@ public class CompressionCodec extends MessageToMessageCodec<ByteBuf, ByteBuf> {
|
|||
private static final int UNCOMPRESSED_CAP = 8 * 1024 * 1024; // 8MiB
|
||||
private int threshold;
|
||||
private VelocityCompressor compressor;
|
||||
private VelocityCompressor candidateCompressor;
|
||||
|
||||
public CompressionCodec(int threshold) {
|
||||
this.threshold = threshold;
|
||||
}
|
||||
|
||||
public int getThreshold() {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
public void setThreshold(int threshold) {
|
||||
this.threshold = threshold;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlerAdded(ChannelHandlerContext ctx) {
|
||||
compressor = Natives.compress.get().create(6);
|
||||
|
||||
var cNative = createCompressor(true);
|
||||
if (isBackend(ctx) && !Natives.compress.getLoadedVariant().equalsIgnoreCase("java")) {
|
||||
// Workaround for Lilypad backend servers
|
||||
compressor = createCompressor(false);
|
||||
candidateCompressor = cNative;
|
||||
} else {
|
||||
compressor = cNative;
|
||||
}
|
||||
}
|
||||
|
||||
private VelocityCompressor createCompressor(boolean allowNative) {
|
||||
var level = VIAaaSConfig.INSTANCE.getCompressionLevel();
|
||||
if (!allowNative) return JavaVelocityCompressor.FACTORY.create(Math.min(level, 9));
|
||||
return Natives.compress.get().create(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlerRemoved(ChannelHandlerContext ctx) {
|
||||
compressor.close();
|
||||
discardCandidate();
|
||||
}
|
||||
|
||||
private boolean isBackend(ChannelHandlerContext ctx) {
|
||||
var handler = ctx.pipeline().get(MinecraftHandler.class);
|
||||
return handler != null && handler.getBackEnd();
|
||||
}
|
||||
|
||||
private void promoteCandidate() {
|
||||
compressor.close();
|
||||
compressor = candidateCompressor;
|
||||
candidateCompressor = null;
|
||||
}
|
||||
|
||||
private void discardCandidate() {
|
||||
if (candidateCompressor == null) return;
|
||||
candidateCompressor.close();
|
||||
candidateCompressor = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -47,7 +90,7 @@ public class CompressionCodec extends MessageToMessageCodec<ByteBuf, ByteBuf> {
|
|||
outBuf.writeByte(0);
|
||||
outBuf.writeBytes(msg);
|
||||
} else {
|
||||
Type.VAR_INT.writePrimitive(outBuf, uncompressedSize);
|
||||
Types.VAR_INT.writePrimitive(outBuf, uncompressedSize);
|
||||
var compatibleIn = MoreByteBufUtils.ensureCompatible(ctx.alloc(), compressor, msg);
|
||||
try {
|
||||
compressor.deflate(compatibleIn, outBuf);
|
||||
|
@ -70,27 +113,53 @@ public class CompressionCodec extends MessageToMessageCodec<ByteBuf, ByteBuf> {
|
|||
protected void decode(ChannelHandlerContext ctx, ByteBuf input, List<Object> out) throws Exception {
|
||||
if (!input.isReadable() || !ctx.channel().isActive()) return;
|
||||
|
||||
var claimedUncompressedSize = Type.VAR_INT.readPrimitive(input);
|
||||
var claimedUncompressedSize = Types.VAR_INT.readPrimitive(input);
|
||||
if (claimedUncompressedSize == 0) { // Uncompressed
|
||||
out.add(input.retain());
|
||||
return;
|
||||
}
|
||||
|
||||
if (claimedUncompressedSize < threshold) {
|
||||
throw new DecoderException("Badly compressed packet - size of $claimedUncompressedSize is below server threshold of $threshold");
|
||||
}
|
||||
// 1.18 clients now accept compressed packets under threshold...?
|
||||
if (claimedUncompressedSize > UNCOMPRESSED_CAP) {
|
||||
throw new DecoderException("Badly compressed packet - size of $claimedUncompressedSize is larger than maximum of $UNCOMPRESSED_CAP");
|
||||
throw new DecoderException("Badly compressed packet - size of " + claimedUncompressedSize + " is larger than maximum of " + UNCOMPRESSED_CAP);
|
||||
}
|
||||
var compatibleIn = MoreByteBufUtils.ensureCompatible(ctx.alloc(), compressor, input);
|
||||
var decompressed = MoreByteBufUtils.preferredBuffer(ctx.alloc(), compressor, claimedUncompressedSize);
|
||||
try {
|
||||
compressor.inflate(compatibleIn, decompressed, claimedUncompressedSize);
|
||||
input.clear();
|
||||
var readerI = compatibleIn.readerIndex();
|
||||
try {
|
||||
compressor.inflate(compatibleIn, decompressed, claimedUncompressedSize);
|
||||
} catch (DataFormatException ex) {
|
||||
// workaround for lilypad
|
||||
if (!ex.getMessage().startsWith("Received a deflate stream that was too large, wanted ")) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
out.add(decompressed.retain());
|
||||
|
||||
testCandidateDecompression(compatibleIn, readerI, claimedUncompressedSize);
|
||||
|
||||
input.clear();
|
||||
} finally {
|
||||
decompressed.release();
|
||||
compatibleIn.release();
|
||||
}
|
||||
}
|
||||
|
||||
private void testCandidateDecompression(ByteBuf in, int readerIndex, int claimedUncompressedSize) {
|
||||
if (candidateCompressor == null) return;
|
||||
in.readerIndex(readerIndex);
|
||||
var testOut = ByteBufAllocator.DEFAULT.buffer();
|
||||
try {
|
||||
candidateCompressor.inflate(in, testOut, claimedUncompressedSize);
|
||||
|
||||
if (Math.random() <= 0.001) { // Runs more tests
|
||||
promoteCandidate();
|
||||
}
|
||||
} catch (DataFormatException eTest) {
|
||||
discardCandidate(); // LilyPad
|
||||
} finally {
|
||||
testOut.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
52
src/main/java/com/viaversion/aas/codec/FrameCodec.java
Normal file
52
src/main/java/com/viaversion/aas/codec/FrameCodec.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
package com.viaversion.aas.codec;
|
||||
|
||||
import com.viaversion.aas.UtilKt;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.exception.CancelDecoderException;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageCodec;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class FrameCodec extends ByteToMessageCodec<ByteBuf> {
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||
if (!ctx.channel().isActive()) {
|
||||
in.clear();
|
||||
// Netty throws an exception when there's no output
|
||||
throw CancelDecoderException.CACHED;
|
||||
}
|
||||
// Ignore, should prevent DoS https://github.com/SpigotMC/BungeeCord/pull/2908
|
||||
|
||||
int index = in.readerIndex();
|
||||
AtomicInteger nByte = new AtomicInteger();
|
||||
int result = in.forEachByte(it -> {
|
||||
nByte.getAndIncrement();
|
||||
boolean hasNext = (it & 0x10000000) != 0;
|
||||
if (nByte.get() > 3) throw UtilKt.getBadLength();
|
||||
return hasNext;
|
||||
});
|
||||
in.readerIndex(index);
|
||||
if (result == -1) return; // not readable
|
||||
|
||||
int length = Types.VAR_INT.readPrimitive(in);
|
||||
|
||||
if (length >= 2097152 || length < 0) throw UtilKt.getBadLength();
|
||||
if (!in.isReadable(length)) {
|
||||
in.readerIndex(index);
|
||||
return;
|
||||
}
|
||||
|
||||
out.add(in.readRetainedSlice(length));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
|
||||
if (msg.readableBytes() >= 2097152) throw UtilKt.getBadLength();
|
||||
Types.VAR_INT.writePrimitive(out, msg.readableBytes());
|
||||
out.writeBytes(msg);
|
||||
}
|
||||
}
|
|
@ -1,10 +1,12 @@
|
|||
package com.viaversion.aas.codec;
|
||||
|
||||
import com.viaversion.aas.UtilKt;
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.aas.codec.packet.PacketRegistry;
|
||||
import com.viaversion.aas.handler.MinecraftHandler;
|
||||
import com.viaversion.aas.util.StacklessException;
|
||||
import com.viaversion.viaversion.api.protocol.packet.Direction;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.exception.CancelEncoderException;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
|
@ -23,10 +25,12 @@ public class MinecraftCodec extends MessageToMessageCodec<ByteBuf, Packet> {
|
|||
|
||||
try {
|
||||
var handler = ctx.pipeline().get(MinecraftHandler.class);
|
||||
var version = handler.getData().getFrontVer();
|
||||
if (version == null) version = ProtocolVersion.unknown;
|
||||
PacketRegistry.INSTANCE.encode(
|
||||
msg,
|
||||
buf,
|
||||
handler.getData().getFrontVer(),
|
||||
version,
|
||||
handler.getFrontEnd() ? Direction.CLIENTBOUND : Direction.SERVERBOUND
|
||||
);
|
||||
out.add(buf.retain());
|
||||
|
@ -42,7 +46,7 @@ public class MinecraftCodec extends MessageToMessageCodec<ByteBuf, Packet> {
|
|||
var handler = ctx.pipeline().get(MinecraftHandler.class);
|
||||
var frontVer = handler.getData().getFrontVer();
|
||||
if (frontVer == null) {
|
||||
frontVer = 0;
|
||||
frontVer = ProtocolVersion.unknown;
|
||||
}
|
||||
out.add(PacketRegistry.INSTANCE.decode(
|
||||
msg,
|
||||
|
@ -51,6 +55,7 @@ public class MinecraftCodec extends MessageToMessageCodec<ByteBuf, Packet> {
|
|||
handler.getFrontEnd() ? Direction.SERVERBOUND : Direction.CLIENTBOUND
|
||||
));
|
||||
if (msg.isReadable()) {
|
||||
UtilKt.getMcLogger().debug("Remaining bytes in packet {}", out);
|
||||
throw new StacklessException("Remaining bytes!!!");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.viaversion.aas.codec.packet;
|
||||
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
@ -9,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
|
|||
* A mutable object which represents a Minecraft packet data
|
||||
*/
|
||||
public interface Packet {
|
||||
void decode(@NotNull ByteBuf byteBuf, int protocolVersion) throws Exception;
|
||||
void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception;
|
||||
|
||||
void encode(@NotNull ByteBuf byteBuf, int protocolVersion) throws Exception;
|
||||
void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package com.viaversion.aas.codec.packet.common;
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AbstractCompression implements Packet {
|
||||
public abstract class AbstractCompression implements Packet {
|
||||
private int threshold;
|
||||
|
||||
public int getThreshold() {
|
||||
|
@ -17,12 +19,12 @@ public class AbstractCompression implements Packet {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, int protocolVersion) throws Exception {
|
||||
threshold = Type.VAR_INT.readPrimitive(byteBuf);
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
threshold = Types.VAR_INT.readPrimitive(byteBuf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, int protocolVersion) throws Exception {
|
||||
Type.VAR_INT.writePrimitive(byteBuf, threshold);
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
Types.VAR_INT.writePrimitive(byteBuf, threshold);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package com.viaversion.aas.codec.packet.common;
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class AbstractCookieRequest implements Packet {
|
||||
private String identifier;
|
||||
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
identifier = Types.STRING.read(byteBuf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
Types.STRING.write(byteBuf, identifier);
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public void setIdentifier(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.viaversion.aas.codec.packet.common;
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class AbstractCookieResponse implements Packet {
|
||||
private String id;
|
||||
private byte[] payload;
|
||||
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
id = Types.STRING.read(byteBuf);
|
||||
payload = Types.OPTIONAL_BYTE_ARRAY_PRIMITIVE.read(byteBuf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
Types.STRING.write(byteBuf, id);
|
||||
Types.OPTIONAL_BYTE_ARRAY_PRIMITIVE.write(byteBuf, payload);
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public byte[] getPayload() {
|
||||
return payload;
|
||||
}
|
||||
|
||||
public void setPayload(byte[] payload) {
|
||||
this.payload = payload;
|
||||
}
|
||||
}
|
|
@ -1,15 +1,16 @@
|
|||
package com.viaversion.aas.codec.packet.common;
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AbstractEmpty implements Packet {
|
||||
public abstract class AbstractEmpty implements Packet {
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, int protocolVersion) throws Exception {
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, int protocolVersion) throws Exception {
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package com.viaversion.aas.codec.packet.common;
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AbstractPing implements Packet {
|
||||
public abstract class AbstractPing implements Packet {
|
||||
private long number;
|
||||
|
||||
public long getNumber() {
|
||||
|
@ -16,12 +17,12 @@ public class AbstractPing implements Packet {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, int protocolVersion) throws Exception {
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
number = byteBuf.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, int protocolVersion) throws Exception {
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
byteBuf.writeLong(number);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
package com.viaversion.aas.codec.packet.common;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.nbt.tag.Tag;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.util.ComponentUtil;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class AbstractSingleChat implements Packet {
|
||||
private JsonElement msg;
|
||||
private Tag msgTag;
|
||||
|
||||
public JsonElement getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(JsonElement msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public Tag getMsgTag() {
|
||||
return msgTag;
|
||||
}
|
||||
|
||||
public void setMsgTag(Tag msgTag) {
|
||||
this.msgTag = msgTag;
|
||||
}
|
||||
|
||||
public JsonElement getMsgAsJson() {
|
||||
if (msg != null) return msg;
|
||||
if (msgTag != null) return JsonParser.parseString(ComponentUtil.tagToJson(this.msgTag).toString());
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setMsgForVersion(JsonElement msg, ProtocolVersion protocolVersion) {
|
||||
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_20_3)) {
|
||||
this.msgTag = ComponentUtil.jsonToTag(com.viaversion.viaversion.libs.gson.JsonParser.parseString(msg.toString()));
|
||||
} else {
|
||||
this.msg = msg;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
if (protocolVersion.olderThan(ProtocolVersion.v1_20_3)) {
|
||||
msg = JsonParser.parseString(Types.STRING.read(byteBuf));
|
||||
} else {
|
||||
msgTag = Types.TAG.read(byteBuf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
if (protocolVersion.olderThan(ProtocolVersion.v1_20_3)) {
|
||||
Types.STRING.write(byteBuf, msg.toString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.viaversion.aas.codec.packet.common;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class AbstractSingleJson implements Packet {
|
||||
private JsonElement msg;
|
||||
|
||||
public JsonElement getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(JsonElement msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
msg = JsonParser.parseString(Types.STRING.read(byteBuf));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
Types.STRING.write(byteBuf, msg.toString());
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package com.viaversion.aas.codec.packet.common;
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AbstractSingleMessage implements Packet {
|
||||
private String msg;
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, int protocolVersion) throws Exception {
|
||||
msg = Type.STRING.read(byteBuf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, int protocolVersion) throws Exception {
|
||||
Type.STRING.write(byteBuf, msg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package com.viaversion.aas.codec.packet.configuration;
|
||||
|
||||
import com.viaversion.aas.codec.packet.common.AbstractCookieRequest;
|
||||
|
||||
public class ConfigurationCookieRequest extends AbstractCookieRequest {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package com.viaversion.aas.codec.packet.configuration;
|
||||
|
||||
import com.viaversion.aas.codec.packet.common.AbstractCookieResponse;
|
||||
|
||||
public class ConfigurationCookieResponse extends AbstractCookieResponse {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package com.viaversion.aas.codec.packet.configuration;
|
||||
|
||||
import com.viaversion.aas.codec.packet.common.AbstractSingleChat;
|
||||
|
||||
public class ConfigurationDisconnect extends AbstractSingleChat {
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.viaversion.aas.codec.packet.configuration;
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ConfigurationKeepAlive implements Packet {
|
||||
private long id;
|
||||
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
this.id = byteBuf.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
byteBuf.writeLong(this.id);
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.viaversion.aas.codec.packet.configuration;
|
||||
|
||||
import com.viaversion.aas.UtilKt;
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ConfigurationPluginMessage implements Packet {
|
||||
private String channel;
|
||||
private byte[] data;
|
||||
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
channel = Types.STRING.read(byteBuf);
|
||||
data = UtilKt.readRemainingBytes(byteBuf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
Types.STRING.write(byteBuf, channel);
|
||||
Types.REMAINING_BYTES.write(byteBuf, data);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package com.viaversion.aas.codec.packet.configuration;
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ConfigurationTransfer implements Packet {
|
||||
|
||||
private String host;
|
||||
private int port;
|
||||
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
host = Types.STRING.read(byteBuf);
|
||||
port = Types.VAR_INT.readPrimitive(byteBuf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
Types.STRING.write(byteBuf, host);
|
||||
Types.VAR_INT.writePrimitive(byteBuf, port);
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.viaversion.aas.codec.packet.configuration;
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class FinishConfig implements Packet {
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package com.viaversion.aas.codec.packet.handshake;
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.aas.util.IntendedState;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class Handshake implements Packet {
|
||||
private int protocolId;
|
||||
private String address;
|
||||
private int port;
|
||||
private IntendedState intendedState;
|
||||
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
protocolId = Types.VAR_INT.readPrimitive(byteBuf);
|
||||
address = Types.STRING.read(byteBuf);
|
||||
port = byteBuf.readUnsignedShort();
|
||||
intendedState = IntendedState.values()[Types.VAR_INT.readPrimitive(byteBuf)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
Types.VAR_INT.writePrimitive(byteBuf, protocolId);
|
||||
Types.STRING.write(byteBuf, address);
|
||||
byteBuf.writeShort(port);
|
||||
Types.VAR_INT.writePrimitive(byteBuf, intendedState.ordinal());
|
||||
}
|
||||
|
||||
public int getProtocolId() {
|
||||
return protocolId;
|
||||
}
|
||||
|
||||
public void setProtocolId(int protocolId) {
|
||||
this.protocolId = protocolId;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public IntendedState getIntendedState() {
|
||||
return intendedState;
|
||||
}
|
||||
|
||||
public void setIntendedState(IntendedState intendedState) {
|
||||
this.intendedState = intendedState;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package com.viaversion.aas.codec.packet.login;
|
||||
|
||||
import com.viaversion.aas.UtilKt;
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.aas.protocol.AspirinProtocolsKt;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.security.KeyFactory;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
|
||||
public class CryptoRequest implements Packet {
|
||||
private String serverId;
|
||||
private PublicKey publicKey;
|
||||
private byte[] nonce;
|
||||
private boolean authenticate;
|
||||
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
serverId = Types.STRING.read(byteBuf);
|
||||
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_8)
|
||||
|| protocolVersion.equalTo(AspirinProtocolsKt.getSharewareVersion())) {
|
||||
publicKey = KeyFactory.getInstance("RSA")
|
||||
.generatePublic(new X509EncodedKeySpec(Types.BYTE_ARRAY_PRIMITIVE.read(byteBuf)));
|
||||
nonce = Types.BYTE_ARRAY_PRIMITIVE.read(byteBuf);
|
||||
} else {
|
||||
publicKey = KeyFactory.getInstance("RSA")
|
||||
.generatePublic(new X509EncodedKeySpec(UtilKt.readByteArray(byteBuf, byteBuf.readUnsignedShort())));
|
||||
nonce = UtilKt.readByteArray(byteBuf, byteBuf.readUnsignedShort());
|
||||
}
|
||||
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_20_5)) {
|
||||
authenticate = byteBuf.readBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
|
||||
Types.STRING.write(byteBuf, serverId);
|
||||
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_8)
|
||||
|| protocolVersion.equalTo(AspirinProtocolsKt.getSharewareVersion())) {
|
||||
Types.BYTE_ARRAY_PRIMITIVE.write(byteBuf, publicKey.getEncoded());
|
||||
Types.BYTE_ARRAY_PRIMITIVE.write(byteBuf, nonce);
|
||||
} else {
|
||||
byte[] encodedKey = publicKey.getEncoded();
|
||||
byteBuf.writeShort(encodedKey.length);
|
||||
byteBuf.writeBytes(encodedKey);
|
||||
byteBuf.writeShort(nonce.length);
|
||||
byteBuf.writeBytes(nonce);
|
||||
}
|
||||
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_20_5)) {
|
||||
byteBuf.writeBoolean(authenticate);
|
||||
}
|
||||
}
|
||||
|
||||
public String getServerId() {
|
||||
return serverId;
|
||||
}
|
||||
|
||||
public void setServerId(String serverId) {
|
||||
this.serverId = serverId;
|
||||
}
|
||||
|
||||
public PublicKey getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
public void setPublicKey(PublicKey publicKey) {
|
||||
this.publicKey = publicKey;
|
||||
}
|
||||
|
||||
public byte[] getNonce() {
|
||||
return nonce;
|
||||
}
|
||||
|
||||
public void setNonce(byte[] nonce) {
|
||||
this.nonce = nonce;
|
||||
}
|
||||
|
||||
public boolean isAuthenticate() {
|
||||
return authenticate;
|
||||
}
|
||||
|
||||
public void setAuthenticate(boolean authenticate) {
|
||||
this.authenticate = authenticate;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.viaversion.aas.codec.packet.login;
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class LoginAck implements Packet {
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package com.viaversion.aas.codec.packet.login;
|
||||
|
||||
import com.viaversion.aas.codec.packet.common.AbstractCookieRequest;
|
||||
|
||||
public class LoginCookieRequest extends AbstractCookieRequest {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package com.viaversion.aas.codec.packet.login;
|
||||
|
||||
import com.viaversion.aas.codec.packet.common.AbstractCookieResponse;
|
||||
|
||||
public class LoginCookieResponse extends AbstractCookieResponse {
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package com.viaversion.aas.codec.packet.login;
|
||||
|
||||
import com.viaversion.aas.codec.packet.common.AbstractSingleMessage;
|
||||
import com.viaversion.aas.codec.packet.common.AbstractSingleJson;
|
||||
|
||||
public class LoginDisconnect extends AbstractSingleMessage {
|
||||
public class LoginDisconnect extends AbstractSingleJson {
|
||||
}
|
||||
|
|
|
@ -1,13 +1,36 @@
|
|||
package com.viaversion.aas.codec.packet.login;
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.minecraft.ProfileKey;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.api.type.types.StringType;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class LoginStart implements Packet {
|
||||
private String username;
|
||||
private ProfileKey profileKey;
|
||||
private UUID profileId;
|
||||
|
||||
public ProfileKey getProfileKey() {
|
||||
return profileKey;
|
||||
}
|
||||
|
||||
public void setProfileKey(ProfileKey profileKey) {
|
||||
this.profileKey = profileKey;
|
||||
}
|
||||
|
||||
public UUID getProfileId() {
|
||||
return profileId;
|
||||
}
|
||||
|
||||
public void setProfileId(UUID profileId) {
|
||||
this.profileId = profileId;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
|
@ -18,12 +41,31 @@ public class LoginStart implements Packet {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, int protocolVersion) throws Exception {
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
username = new StringType(16).read(byteBuf);
|
||||
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_19)
|
||||
&& protocolVersion.olderThan(ProtocolVersion.v1_19_3)) {
|
||||
profileKey = Types.OPTIONAL_PROFILE_KEY.read(byteBuf);
|
||||
}
|
||||
|
||||
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_20_2)) {
|
||||
profileId = Types.UUID.read(byteBuf);
|
||||
} else if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_19_1)) {
|
||||
profileId = Types.OPTIONAL_UUID.read(byteBuf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, int protocolVersion) throws Exception {
|
||||
Type.STRING.write(byteBuf, username);
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
Types.STRING.write(byteBuf, username);
|
||||
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_19)
|
||||
&& protocolVersion.olderThan(ProtocolVersion.v1_19_3)) {
|
||||
Types.OPTIONAL_PROFILE_KEY.write(byteBuf, profileKey);
|
||||
}
|
||||
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_20_2)) {
|
||||
Types.UUID.write(byteBuf, profileId);
|
||||
} else if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_19_1)) {
|
||||
Types.OPTIONAL_UUID.write(byteBuf, profileId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package com.viaversion.aas.codec.packet.login;
|
||||
|
||||
import com.viaversion.aas.UtilKt;
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PluginRequest implements Packet {
|
||||
private int id;
|
||||
private String channel;
|
||||
private byte[] data;
|
||||
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
id = Types.VAR_INT.readPrimitive(byteBuf);
|
||||
channel = Types.STRING.read(byteBuf);
|
||||
data = UtilKt.readRemainingBytes(byteBuf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
Types.VAR_INT.writePrimitive(byteBuf, id);
|
||||
Types.STRING.write(byteBuf, channel);
|
||||
byteBuf.writeBytes(data);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public void setChannel(String channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.viaversion.aas.codec.packet.login;
|
||||
|
||||
import com.viaversion.aas.UtilKt;
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PluginResponse implements Packet {
|
||||
private int id;
|
||||
private boolean success;
|
||||
private byte[] data;
|
||||
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
id = Types.VAR_INT.readPrimitive(byteBuf);
|
||||
success = byteBuf.readBoolean();
|
||||
if (success) {
|
||||
data = UtilKt.readRemainingBytes(byteBuf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
Types.VAR_INT.writePrimitive(byteBuf, id);
|
||||
byteBuf.writeBoolean(success);
|
||||
if (success) {
|
||||
byteBuf.writeBytes(data);
|
||||
}
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public void setSuccess(boolean success) {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.viaversion.aas.codec.packet.play;
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ConfigurationAck implements Packet {
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package com.viaversion.aas.codec.packet.play;
|
||||
|
||||
import com.viaversion.aas.codec.packet.common.AbstractSingleMessage;
|
||||
import com.viaversion.aas.codec.packet.common.AbstractSingleChat;
|
||||
|
||||
public class Kick extends AbstractSingleMessage {
|
||||
public class Kick extends AbstractSingleChat {
|
||||
}
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
package com.viaversion.aas.codec.packet.play;
|
||||
|
||||
import com.viaversion.aas.UtilKt;
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PluginMessage implements Packet {
|
||||
private String channel;
|
||||
private byte[] data;
|
||||
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
channel = Types.STRING.read(byteBuf);
|
||||
if (protocolVersion.olderThanOrEqualTo(ProtocolVersion.v1_7_6)) {
|
||||
data = UtilKt.readByteArray(byteBuf, readExtendedForgeShort(byteBuf));
|
||||
} else {
|
||||
data = UtilKt.readRemainingBytes(byteBuf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
Types.STRING.write(byteBuf, channel);
|
||||
if (protocolVersion.olderThanOrEqualTo(ProtocolVersion.v1_7_6)) {
|
||||
writeExtendedForgeShort(byteBuf, data.length);
|
||||
}
|
||||
byteBuf.writeBytes(data);
|
||||
}
|
||||
|
||||
// stolen from https://github.com/VelocityPowered/Velocity/blob/27ccb9d387fc9a0aecd5c4b570d7d957558efddc/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java#L418
|
||||
private int readExtendedForgeShort(ByteBuf buf) {
|
||||
int low = buf.readUnsignedShort();
|
||||
int high = 0;
|
||||
if ((low & 0x8000) != 0) {
|
||||
low = low & 0x7FFF;
|
||||
high = buf.readUnsignedByte();
|
||||
}
|
||||
return ((high & 0xFF) << 15) | low;
|
||||
}
|
||||
|
||||
private void writeExtendedForgeShort(ByteBuf buf, int toWrite) {
|
||||
int low = toWrite & 0x7FFF;
|
||||
int high = (toWrite & 0x7F8000) << 15;
|
||||
if (high != 0) {
|
||||
low = low | 0x8000;
|
||||
}
|
||||
buf.writeShort(low);
|
||||
if (high != 0) {
|
||||
buf.writeByte(high);
|
||||
}
|
||||
}
|
||||
|
||||
public String getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public void setChannel(String channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
package com.viaversion.aas.codec.packet.play;
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.minecraft.PlayerMessageSignature;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ServerboundChatCommand implements Packet {
|
||||
private String message;
|
||||
private long timestamp;
|
||||
private long salt;
|
||||
private ArgumentSignature[] signatures;
|
||||
private boolean signedPreview;
|
||||
private PlayerMessageSignature[] lastSeenMessages;
|
||||
private PlayerMessageSignature lastReceivedMessage;
|
||||
|
||||
|
||||
public static class ArgumentSignature {
|
||||
private String argumentName;
|
||||
private byte[] signature;
|
||||
|
||||
public ArgumentSignature(String argumentName, byte[] signature) {
|
||||
this.argumentName = argumentName;
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public String getArgumentName() {
|
||||
return argumentName;
|
||||
}
|
||||
|
||||
public void setArgumentName(String argumentName) {
|
||||
this.argumentName = argumentName;
|
||||
}
|
||||
|
||||
public byte[] getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public void setSignature(byte[] signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
message = Types.STRING.read(byteBuf);
|
||||
timestamp = byteBuf.readLong();
|
||||
salt = byteBuf.readLong();
|
||||
signatures = new ArgumentSignature[Types.VAR_INT.readPrimitive(byteBuf)];
|
||||
for (int i = 0; i < signatures.length; i++) {
|
||||
signatures[i] = new ArgumentSignature(Types.STRING.read(byteBuf), Types.BYTE_ARRAY_PRIMITIVE.read(byteBuf));
|
||||
}
|
||||
signedPreview = byteBuf.readBoolean();
|
||||
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_19_1)) {
|
||||
lastSeenMessages = Types.PLAYER_MESSAGE_SIGNATURE_ARRAY.read(byteBuf);
|
||||
lastReceivedMessage = Types.OPTIONAL_PLAYER_MESSAGE_SIGNATURE.read(byteBuf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
Types.STRING.write(byteBuf, message);
|
||||
byteBuf.writeLong(timestamp);
|
||||
byteBuf.writeLong(salt);
|
||||
Types.VAR_INT.writePrimitive(byteBuf, signatures.length);
|
||||
for (ArgumentSignature signature : signatures) {
|
||||
Types.STRING.write(byteBuf, signature.getArgumentName());
|
||||
Types.BYTE_ARRAY_PRIMITIVE.write(byteBuf, signature.getSignature());
|
||||
}
|
||||
byteBuf.writeBoolean(signedPreview);
|
||||
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_19_1)) {
|
||||
Types.PLAYER_MESSAGE_SIGNATURE_ARRAY.write(byteBuf, lastSeenMessages);
|
||||
Types.OPTIONAL_PLAYER_MESSAGE_SIGNATURE.write(byteBuf, lastReceivedMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public ArgumentSignature[] getSignatures() {
|
||||
return signatures;
|
||||
}
|
||||
|
||||
public void setSignatures(ArgumentSignature[] signatures) {
|
||||
this.signatures = signatures;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public long getSalt() {
|
||||
return salt;
|
||||
}
|
||||
|
||||
public void setSalt(long salt) {
|
||||
this.salt = salt;
|
||||
}
|
||||
|
||||
public boolean isSignedPreview() {
|
||||
return signedPreview;
|
||||
}
|
||||
|
||||
public void setSignedPreview(boolean signedPreview) {
|
||||
this.signedPreview = signedPreview;
|
||||
}
|
||||
|
||||
public PlayerMessageSignature[] getLastSeenMessages() {
|
||||
return lastSeenMessages;
|
||||
}
|
||||
|
||||
public void setLastSeenMessages(PlayerMessageSignature[] lastSeenMessages) {
|
||||
this.lastSeenMessages = lastSeenMessages;
|
||||
}
|
||||
|
||||
public PlayerMessageSignature getLastReceivedMessage() {
|
||||
return lastReceivedMessage;
|
||||
}
|
||||
|
||||
public void setLastReceivedMessage(PlayerMessageSignature lastReceivedMessage) {
|
||||
this.lastReceivedMessage = lastReceivedMessage;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package com.viaversion.aas.codec.packet.play;
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.viaversion.api.minecraft.PlayerMessageSignature;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ServerboundChatMessage implements Packet {
|
||||
private String message;
|
||||
private long timestamp;
|
||||
private long salt;
|
||||
private byte[] signature;
|
||||
private boolean signedPreview;
|
||||
private PlayerMessageSignature[] lastSeenMessages;
|
||||
private PlayerMessageSignature lastReceivedMessage;
|
||||
|
||||
@Override
|
||||
public void decode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
message = Types.STRING.read(byteBuf);
|
||||
timestamp = byteBuf.readLong();
|
||||
salt = byteBuf.readLong();
|
||||
signature = Types.BYTE_ARRAY_PRIMITIVE.read(byteBuf);
|
||||
signedPreview = byteBuf.readBoolean();
|
||||
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_19_1)) {
|
||||
lastSeenMessages = Types.PLAYER_MESSAGE_SIGNATURE_ARRAY.read(byteBuf);
|
||||
lastReceivedMessage = Types.OPTIONAL_PLAYER_MESSAGE_SIGNATURE.read(byteBuf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull ByteBuf byteBuf, ProtocolVersion protocolVersion) throws Exception {
|
||||
Types.STRING.write(byteBuf, message);
|
||||
byteBuf.writeLong(timestamp);
|
||||
byteBuf.writeLong(salt);
|
||||
Types.BYTE_ARRAY_PRIMITIVE.write(byteBuf, signature);
|
||||
byteBuf.writeBoolean(signedPreview);
|
||||
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_19_1)) {
|
||||
Types.PLAYER_MESSAGE_SIGNATURE_ARRAY.write(byteBuf, lastSeenMessages);
|
||||
Types.OPTIONAL_PLAYER_MESSAGE_SIGNATURE.write(byteBuf, lastReceivedMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public long getSalt() {
|
||||
return salt;
|
||||
}
|
||||
|
||||
public void setSalt(long salt) {
|
||||
this.salt = salt;
|
||||
}
|
||||
|
||||
public byte[] getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public void setSignature(byte[] signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public boolean isSignedPreview() {
|
||||
return signedPreview;
|
||||
}
|
||||
|
||||
public void setSignedPreview(boolean signedPreview) {
|
||||
this.signedPreview = signedPreview;
|
||||
}
|
||||
|
||||
public PlayerMessageSignature[] getLastSeenMessages() {
|
||||
return lastSeenMessages;
|
||||
}
|
||||
|
||||
public void setLastSeenMessages(PlayerMessageSignature[] lastSeenMessages) {
|
||||
this.lastSeenMessages = lastSeenMessages;
|
||||
}
|
||||
|
||||
public PlayerMessageSignature getLastReceivedMessage() {
|
||||
return lastReceivedMessage;
|
||||
}
|
||||
|
||||
public void setLastReceivedMessage(PlayerMessageSignature lastReceivedMessage) {
|
||||
this.lastReceivedMessage = lastReceivedMessage;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package com.viaversion.aas.codec.packet.status;
|
||||
|
||||
import com.viaversion.aas.codec.packet.common.AbstractSingleMessage;
|
||||
import com.viaversion.aas.codec.packet.common.AbstractSingleJson;
|
||||
|
||||
public class StatusResponse extends AbstractSingleMessage {
|
||||
public class StatusResponse extends AbstractSingleJson {
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.viaversion.aas.config;
|
||||
|
||||
import com.viaversion.aas.platform.AspirinPlatform;
|
||||
import com.viaversion.viaversion.configuration.AbstractViaConfig;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -9,11 +10,11 @@ import java.util.Map;
|
|||
|
||||
public class AspirinViaConfig extends AbstractViaConfig {
|
||||
{
|
||||
reloadConfig();
|
||||
reload();
|
||||
}
|
||||
|
||||
public AspirinViaConfig() {
|
||||
super(new File("config/viaversion.yml"));
|
||||
super(new File("config/viaversion.yml"), AspirinPlatform.INSTANCE.getLogger());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -29,8 +30,7 @@ public class AspirinViaConfig extends AbstractViaConfig {
|
|||
@Override
|
||||
public List<String> getUnsupportedOptions() {
|
||||
return List.of(
|
||||
"anti-xray-patch", "bungee-ping-interval",
|
||||
"bungee-ping-save", "bungee-servers", "quick-move-action-fix", "nms-player-ticking",
|
||||
"anti-xray-patch", "quick-move-action-fix", "nms-player-ticking",
|
||||
"item-cache", "velocity-ping-interval", "velocity-ping-save", "velocity-servers",
|
||||
"blockconnection-method", "change-1_9-hitbox", "change-1_14-hitbox", "block-protocols",
|
||||
"block-disconnect-msg", "reload-disconnect-msg", "max-pps", "max-pps-kick-msg", "tracking-period",
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
package com.viaversion.aas.handler.state;
|
||||
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.viaversion.aas.UtilKt;
|
||||
import com.viaversion.aas.codec.packet.Packet;
|
||||
import com.viaversion.aas.codec.packet.configuration.ConfigurationDisconnect;
|
||||
import com.viaversion.aas.codec.packet.configuration.FinishConfig;
|
||||
import com.viaversion.aas.handler.HandlerUtilKt;
|
||||
import com.viaversion.aas.handler.MinecraftHandler;
|
||||
import com.viaversion.viaversion.api.protocol.packet.State;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ConfigurationState implements ConnectionState {
|
||||
private boolean kickedByServer = false;
|
||||
@NotNull
|
||||
@Override
|
||||
public State getState() {
|
||||
return State.CONFIGURATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePacket(@NotNull MinecraftHandler handler, @NotNull ChannelHandlerContext ctx, @NotNull Packet packet) {
|
||||
if (packet instanceof FinishConfig) handleFinish(handler);
|
||||
if (packet instanceof ConfigurationDisconnect) handleDisconnect(handler, (ConfigurationDisconnect) packet);
|
||||
HandlerUtilKt.forward(handler, ReferenceCountUtil.retain(packet), false);
|
||||
}
|
||||
|
||||
private void handleDisconnect(MinecraftHandler handler, ConfigurationDisconnect packet) {
|
||||
kickedByServer = true;
|
||||
UtilKt.getMcLogger().debug(
|
||||
"{} disconnected on config: {}",
|
||||
handler.endRemoteAddress.toString(),
|
||||
packet.getMsgAsJson()
|
||||
);
|
||||
}
|
||||
|
||||
private void handleFinish(MinecraftHandler handler) {
|
||||
if (handler.getBackEnd()) return;
|
||||
handler.getData().setState(new PlayState());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getLogDcInfo() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getKickedByServer() {
|
||||
return kickedByServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(@NotNull MinecraftHandler handler, @NotNull String msg) {
|
||||
ConnectionState.DefaultImpls.disconnect(this, handler, msg);
|
||||
var packet = new ConfigurationDisconnect();
|
||||
packet.setMsgForVersion(new JsonPrimitive("[VIAaaS] §c" + msg), handler.getData().getFrontVer());
|
||||
UtilKt.writeFlushClose(handler.getData().getFrontChannel(), packet, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInactivated(@NotNull MinecraftHandler handler) {
|
||||
ConnectionState.DefaultImpls.onInactivated(this, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(@NotNull MinecraftHandler handler) {
|
||||
}
|
||||
}
|
|
@ -41,4 +41,14 @@ public class StatusKicked implements ConnectionState {
|
|||
public void onInactivated(@NotNull MinecraftHandler handler) {
|
||||
ConnectionState.DefaultImpls.onInactivated(this, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(@NotNull MinecraftHandler handler) {
|
||||
UtilKt.setAutoRead(handler.getData().getFrontChannel(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getKickedByServer() {
|
||||
return ConnectionState.DefaultImpls.getKickedByServer(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,20 @@
|
|||
package com.viaversion.aas.platform;
|
||||
|
||||
import com.viaversion.viaversion.ViaAPIBase;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class AspirinApi extends ViaAPIBase<UUID> {
|
||||
public class AspirinApi extends ViaAPIBase<UserConnection> {
|
||||
@Override
|
||||
public ProtocolVersion getPlayerProtocolVersion(UserConnection player) {
|
||||
return player.getProtocolInfo().protocolVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendRawPacket(UserConnection player, ByteBuf packet) {
|
||||
player.scheduleSendRawPacket(packet);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package com.viaversion.aas.platform;
|
||||
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import net.raphimc.viaaprilfools.platform.ViaAprilFoolsPlatform;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class AspirinAprilFools implements ViaAprilFoolsPlatform {
|
||||
private final Logger logger = Logger.getLogger("ViaAprilFools");
|
||||
@Override
|
||||
public Logger getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
init(new File(getDataFolder(), "viaaprilfools.yml"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDataFolder() {
|
||||
return Via.getPlatform().getDataFolder();
|
||||
}
|
||||
}
|
|
@ -1,23 +1,28 @@
|
|||
package com.viaversion.aas.platform;
|
||||
|
||||
import com.viaversion.viabackwards.api.ViaBackwardsPlatform;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class AspirinBackwards implements ViaBackwardsPlatform {
|
||||
private Logger logger = Logger.getLogger("ViaBackwards");
|
||||
private final Logger logger = Logger.getLogger("ViaBackwards");
|
||||
@Override
|
||||
public Logger getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
init(new File(getDataFolder(), "viabackwards.yml"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDataFolder() {
|
||||
return new File("config/viabackwards");
|
||||
return Via.getPlatform().getDataFolder();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,11 @@ import com.viaversion.viaversion.api.platform.ViaInjector;
|
|||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.libs.fastutil.ints.IntLinkedOpenHashSet;
|
||||
import com.viaversion.viaversion.libs.fastutil.ints.IntSortedSet;
|
||||
import com.viaversion.viaversion.libs.fastutil.objects.ObjectLinkedOpenHashSet;
|
||||
import com.viaversion.viaversion.libs.gson.JsonObject;
|
||||
import de.gerrygames.viarewind.sponge.VersionInfo;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSortedSet;
|
||||
|
||||
import java.util.SortedSet;
|
||||
|
||||
public class AspirinInjector implements ViaInjector {
|
||||
@Override
|
||||
|
@ -17,8 +20,8 @@ public class AspirinInjector implements ViaInjector {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int getServerProtocolVersion() {
|
||||
return getServerProtocolVersions().firstInt();
|
||||
public ProtocolVersion getServerProtocolVersion() {
|
||||
return getServerProtocolVersions().first();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -33,19 +36,13 @@ public class AspirinInjector implements ViaInjector {
|
|||
|
||||
@Override
|
||||
public JsonObject getDump() {
|
||||
var obj = new JsonObject();
|
||||
obj.addProperty("ViaRewind version", VersionInfo.VERSION);
|
||||
return obj;
|
||||
return new JsonObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntSortedSet getServerProtocolVersions() {
|
||||
var versions = new IntLinkedOpenHashSet();
|
||||
versions.add(ProtocolVersion.v1_7_1.getOriginalVersion());
|
||||
versions.add(ProtocolVersion.getProtocols()
|
||||
.stream()
|
||||
.mapToInt(ProtocolVersion::getOriginalVersion)
|
||||
.max().orElseThrow());
|
||||
public SortedSet<ProtocolVersion> getServerProtocolVersions() {
|
||||
var versions = new ObjectLinkedOpenHashSet<ProtocolVersion>();
|
||||
versions.addAll(ProtocolVersion.getProtocols());
|
||||
return versions;
|
||||
}
|
||||
}
|
||||
|
|
23
src/main/java/com/viaversion/aas/platform/AspirinLegacy.java
Normal file
23
src/main/java/com/viaversion/aas/platform/AspirinLegacy.java
Normal file
|
@ -0,0 +1,23 @@
|
|||
package com.viaversion.aas.platform;
|
||||
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import net.raphimc.vialegacy.platform.ViaLegacyPlatform;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class AspirinLegacy implements ViaLegacyPlatform {
|
||||
@Override
|
||||
public Logger getLogger() {
|
||||
return Via.getPlatform().getLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDataFolder() {
|
||||
return Via.getPlatform().getDataFolder();
|
||||
}
|
||||
|
||||
public void init() {
|
||||
init(new File(getDataFolder(), "vialegacy.yml"));
|
||||
}
|
||||
}
|
|
@ -1,17 +1,26 @@
|
|||
package com.viaversion.aas.platform;
|
||||
|
||||
import com.viaversion.aas.provider.AspirinVersionProvider;
|
||||
import com.viaversion.aas.provider.*;
|
||||
import com.viaversion.viabackwards.protocol.v1_20_5to1_20_3.provider.TransferProvider;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.platform.ViaPlatformLoader;
|
||||
import com.viaversion.viaversion.api.protocol.version.VersionProvider;
|
||||
import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
|
||||
import com.viaversion.viaversion.velocity.providers.VelocityMovementTransmitter;
|
||||
import com.viaversion.viaversion.protocols.v1_8to1_9.provider.CompressionProvider;
|
||||
import net.raphimc.vialegacy.protocol.release.r1_6_4tor1_7_2_5.provider.EncryptionProvider;
|
||||
import net.raphimc.vialegacy.protocol.release.r1_7_6_10tor1_8.provider.GameProfileFetcher;
|
||||
|
||||
public class AspirinLoader implements ViaPlatformLoader {
|
||||
@Override
|
||||
public void load() {
|
||||
Via.getManager().getProviders().use(MovementTransmitterProvider.class, new VelocityMovementTransmitter());
|
||||
Via.getManager().getProviders().use(VersionProvider.class, new AspirinVersionProvider());
|
||||
Via.getManager().getProviders().use(CompressionProvider.class, new AspirinCompressionProvider());
|
||||
|
||||
//ViaBackwards
|
||||
Via.getManager().getProviders().use(TransferProvider.class, new AspirinTransferProvider());
|
||||
|
||||
//ViaLegacy
|
||||
Via.getManager().getProviders().use(GameProfileFetcher.class, new AspirinProfileProvider());
|
||||
Via.getManager().getProviders().use(EncryptionProvider.class, new AspirinEncryptionProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,13 +1,24 @@
|
|||
package com.viaversion.aas.platform;
|
||||
|
||||
import de.gerrygames.viarewind.api.ViaRewindPlatform;
|
||||
import com.viaversion.viarewind.api.ViaRewindPlatform;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class AspirinRewind implements ViaRewindPlatform {
|
||||
private Logger logger = Logger.getLogger("ViaRewind");
|
||||
private final Logger logger = Logger.getLogger("ViaRewind");
|
||||
@Override
|
||||
public Logger getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
init(new File(getDataFolder(), "viarewind.yml"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDataFolder() {
|
||||
return Via.getPlatform().getDataFolder();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,11 +13,6 @@ public class FutureTask implements PlatformTask<Future<?>> {
|
|||
this.object = object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Future<?> getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
object.cancel(false);
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package com.viaversion.aas.provider;
|
||||
|
||||
import com.viaversion.aas.handler.HandlerUtilKt;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.protocols.v1_8to1_9.provider.CompressionProvider;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class AspirinCompressionProvider extends CompressionProvider {
|
||||
@Override
|
||||
public void handlePlayCompression(UserConnection user, int threshold) {
|
||||
HandlerUtilKt.setCompression(Objects.requireNonNull(user.getChannel()), threshold);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.viaversion.aas.provider;
|
||||
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import net.raphimc.vialegacy.protocol.release.r1_6_4tor1_7_2_5.provider.EncryptionProvider;
|
||||
|
||||
public class AspirinEncryptionProvider extends EncryptionProvider {
|
||||
@Override
|
||||
public void enableDecryption(UserConnection user) {
|
||||
throw new UnsupportedOperationException("todo"); // todo implement this
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.viaversion.aas.provider;
|
||||
|
||||
import com.viaversion.aas.UtilKt;
|
||||
import net.raphimc.vialegacy.protocol.release.r1_7_6_10tor1_8.model.GameProfile;
|
||||
import net.raphimc.vialegacy.protocol.release.r1_7_6_10tor1_8.provider.GameProfileFetcher;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
// todo implement an api without blocking
|
||||
public class AspirinProfileProvider extends GameProfileFetcher {
|
||||
@Override
|
||||
public UUID loadMojangUUID(String playerName) {
|
||||
return UtilKt.generateOfflinePlayerUuid(playerName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameProfile loadGameProfile(UUID uuid) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.viaversion.aas.provider;
|
||||
|
||||
import com.viaversion.viabackwards.protocol.v1_20_5to1_20_3.provider.TransferProvider;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
|
||||
public class AspirinTransferProvider implements TransferProvider {
|
||||
|
||||
@Override
|
||||
public void connectToServer(UserConnection userConnection, String s, int i) {
|
||||
}
|
||||
}
|
|
@ -2,11 +2,12 @@ package com.viaversion.aas.provider;
|
|||
|
||||
import com.viaversion.aas.handler.MinecraftHandler;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.protocols.base.BaseVersionProvider;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.protocol.version.BaseVersionProvider;
|
||||
|
||||
public class AspirinVersionProvider extends BaseVersionProvider {
|
||||
@Override
|
||||
public int getClosestServerProtocol(UserConnection connection) throws Exception {
|
||||
public ProtocolVersion getClosestServerProtocol(UserConnection connection) throws Exception {
|
||||
var ver = connection.getChannel().pipeline().get(MinecraftHandler.class).getData().getBackServerVer();
|
||||
if (ver != null) return ver;
|
||||
return super.getClosestServerProtocol(connection);
|
||||
|
|
|
@ -5,13 +5,11 @@ import com.google.common.primitives.Ints;
|
|||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import kotlin.text.StringsKt;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class AddressParser {
|
||||
public Integer protocol;
|
||||
public ProtocolVersion protocol;
|
||||
public String viaSuffix;
|
||||
public String serverAddress;
|
||||
public String viaOptions;
|
||||
|
@ -19,20 +17,12 @@ public class AddressParser {
|
|||
public String username;
|
||||
public Boolean online;
|
||||
|
||||
public AddressParser parse(String address, String viaHostName) {
|
||||
address = StringsKt.removeSuffix(address, ".");
|
||||
String suffixRemoved = StringsKt.removeSuffix(address, "." + viaHostName);
|
||||
|
||||
if (suffixRemoved.equals(address)) {
|
||||
serverAddress = address;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AddressParser parse(String address) {
|
||||
boolean stopOptions = false;
|
||||
List<String> optionsParts = new ArrayList<>();
|
||||
List<String> serverParts = new ArrayList<>();
|
||||
|
||||
for (String part : Lists.reverse(Arrays.asList(suffixRemoved.split(Pattern.quote("."))))) {
|
||||
for (String part : Lists.reverse(Arrays.asList(address.split(Pattern.quote("."))))) {
|
||||
if (!stopOptions && parseOption(part)) {
|
||||
optionsParts.add(part);
|
||||
continue;
|
||||
|
@ -43,7 +33,28 @@ public class AddressParser {
|
|||
|
||||
serverAddress = String.join(".", Lists.reverse(serverParts));
|
||||
viaOptions = String.join(".", Lists.reverse(optionsParts));
|
||||
viaSuffix = viaHostName;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AddressParser parse(String rawAddress, List<String> viaHostName) {
|
||||
String address = StringsKt.removeSuffix(rawAddress, ".");
|
||||
|
||||
String suffix = viaHostName.stream()
|
||||
.filter(s -> StringsKt.endsWith("." + address, s, false))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
|
||||
String suffixRemoved;
|
||||
if (suffix != null) {
|
||||
suffixRemoved = StringsKt.removeSuffix(address, "." + suffix);
|
||||
} else {
|
||||
serverAddress = address;
|
||||
return this;
|
||||
}
|
||||
|
||||
parse(suffixRemoved);
|
||||
viaSuffix = suffix;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -61,7 +72,7 @@ public class AddressParser {
|
|||
}
|
||||
|
||||
String arg = part.substring(2);
|
||||
switch (option) {
|
||||
switch (option.toLowerCase(Locale.ROOT)) {
|
||||
case "o": {
|
||||
parseOnlineMode(arg);
|
||||
break;
|
||||
|
@ -102,10 +113,11 @@ public class AddressParser {
|
|||
}
|
||||
|
||||
public void parseProtocol(String arg) {
|
||||
protocol = Ints.tryParse(arg);
|
||||
if (protocol == null) {
|
||||
ProtocolVersion ver = ProtocolVersion.getClosest(arg.replace("_", "."));
|
||||
if (ver != null) protocol = ver.getVersion();
|
||||
final Integer protocolId = Ints.tryParse(arg);
|
||||
if (protocolId == null) {
|
||||
protocol = ProtocolVersion.getClosest(arg.replace("_", "."));
|
||||
} else {
|
||||
protocol = ProtocolVersion.getProtocol(protocolId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
20
src/main/java/com/viaversion/aas/util/IntendedState.java
Normal file
20
src/main/java/com/viaversion/aas/util/IntendedState.java
Normal file
|
@ -0,0 +1,20 @@
|
|||
package com.viaversion.aas.util;
|
||||
|
||||
import com.viaversion.viaversion.api.protocol.packet.State;
|
||||
|
||||
public enum IntendedState {
|
||||
INVALID(null),
|
||||
STATUS(State.STATUS),
|
||||
LOGIN(State.LOGIN),
|
||||
TRANSFER(State.LOGIN);
|
||||
|
||||
private final State state;
|
||||
|
||||
IntendedState(State state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
}
|
41
src/main/java/com/viaversion/aas/util/SignableProperty.java
Normal file
41
src/main/java/com/viaversion/aas/util/SignableProperty.java
Normal file
|
@ -0,0 +1,41 @@
|
|||
package com.viaversion.aas.util;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class SignableProperty {
|
||||
private String key;
|
||||
private String value;
|
||||
@Nullable
|
||||
private String signature;
|
||||
|
||||
public SignableProperty(String key, String value, @Nullable String signature) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public void setSignature(@Nullable String signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
}
|
|
@ -7,17 +7,19 @@ import com.viaversion.aas.config.VIAaaSConfig
|
|||
import com.viaversion.aas.handler.FrontEndInit
|
||||
import com.viaversion.aas.handler.MinecraftHandler
|
||||
import com.viaversion.aas.platform.AspirinPlatform
|
||||
import com.viaversion.aas.web.WebDashboardServer
|
||||
import com.viaversion.aas.web.WebServer
|
||||
import com.viaversion.viaversion.ViaManagerImpl
|
||||
import com.viaversion.viaversion.api.Via
|
||||
import com.viaversion.viaversion.api.protocol.packet.State
|
||||
import com.viaversion.viaversion.update.Version
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.call.body
|
||||
import io.ktor.client.engine.java.*
|
||||
import io.ktor.client.features.*
|
||||
import io.ktor.client.features.json.*
|
||||
import io.ktor.client.plugins.*
|
||||
import io.ktor.client.plugins.contentnegotiation.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.network.tls.certificates.*
|
||||
import io.ktor.serialization.gson.*
|
||||
import io.ktor.server.engine.*
|
||||
import io.ktor.server.netty.*
|
||||
import io.netty.bootstrap.ServerBootstrap
|
||||
|
@ -27,9 +29,12 @@ import io.netty.channel.WriteBufferWaterMark
|
|||
import io.netty.resolver.dns.DnsNameResolverBuilder
|
||||
import io.netty.util.concurrent.Future
|
||||
import java.io.File
|
||||
import java.net.InetAddress
|
||||
import java.lang.management.ManagementFactory
|
||||
import java.security.KeyPair
|
||||
import java.security.KeyPairGenerator
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.DurationUnit
|
||||
|
||||
object AspirinServer {
|
||||
var ktorServer: NettyApplicationEngine? = null
|
||||
|
@ -40,20 +45,31 @@ object AspirinServer {
|
|||
.readText()
|
||||
).asJsonObject["version"].asString
|
||||
val cleanedVer get() = version.substringBefore("+")
|
||||
var viaWebServer = WebDashboardServer()
|
||||
var viaWebServer = WebServer()
|
||||
private var serverFinishing = CompletableFuture<Unit>()
|
||||
private var finishedFuture = CompletableFuture<Unit>()
|
||||
private val initFuture = CompletableFuture<Unit>()
|
||||
val bufferWaterMark = WriteBufferWaterMark(512 * 1024, 2048 * 1024)
|
||||
|
||||
// Minecraft doesn't have forward secrecy
|
||||
val mcCryptoKey = KeyPairGenerator.getInstance("RSA").let {
|
||||
it.initialize(VIAaaSConfig.mcRsaSize) // https://stackoverflow.com/questions/1904516/is-1024-bit-rsa-secure
|
||||
it.genKeyPair()
|
||||
// Minecraft crypto is very cursed: https://github.com/VelocityPowered/Velocity/issues/568
|
||||
var mcCryptoKey = generateKey()
|
||||
fun generateKey(): KeyPair {
|
||||
return KeyPairGenerator.getInstance("RSA").let {
|
||||
it.initialize(2048)
|
||||
it.genKeyPair()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
// This VIAaaS code idea is even more cursed
|
||||
AspirinPlatform.runRepeatingSync({
|
||||
mcCryptoKey = generateKey()
|
||||
}, 10 * 60 * 20L) // regenerate each 10 min
|
||||
}
|
||||
|
||||
val parentLoop = eventLoopGroup()
|
||||
val childLoop = eventLoopGroup()
|
||||
var chFuture: ChannelFuture? = null
|
||||
var chFutures = mutableListOf<ChannelFuture>()
|
||||
val dnsResolver = DnsNameResolverBuilder(childLoop.next())
|
||||
.socketChannelFactory(channelSocketFactory(childLoop))
|
||||
.channelFactory(channelDatagramFactory(childLoop))
|
||||
|
@ -62,8 +78,8 @@ object AspirinServer {
|
|||
install(UserAgent) {
|
||||
agent = "VIAaaS/$cleanedVer"
|
||||
}
|
||||
install(JsonFeature) {
|
||||
serializer = GsonSerializer()
|
||||
install(ContentNegotiation) {
|
||||
gson()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,11 +94,10 @@ object AspirinServer {
|
|||
mainFinishSignal()
|
||||
ktorServer?.stop(1000, 1000)
|
||||
httpClient.close()
|
||||
listOf<Future<*>?>(
|
||||
chFuture?.channel()?.close(),
|
||||
(chFutures.map { it.channel().close() } + listOf<Future<*>?>(
|
||||
parentLoop.shutdownGracefully(),
|
||||
childLoop.shutdownGracefully()
|
||||
)
|
||||
))
|
||||
.forEach { it?.sync() }
|
||||
}
|
||||
}
|
||||
|
@ -98,25 +113,38 @@ object AspirinServer {
|
|||
fun mainStartSignal() = initFuture.complete(Unit)
|
||||
|
||||
fun listenPorts(args: Array<String>) {
|
||||
chFuture = ServerBootstrap()
|
||||
val serverBootstrap = ServerBootstrap()
|
||||
.group(parentLoop, childLoop)
|
||||
.channelFactory(channelServerSocketFactory(parentLoop))
|
||||
.childHandler(FrontEndInit)
|
||||
.childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, bufferWaterMark)
|
||||
.childOption(ChannelOption.IP_TOS, 0x18)
|
||||
.childOption(ChannelOption.TCP_NODELAY, true)
|
||||
.bind(InetAddress.getByName(VIAaaSConfig.bindAddress), VIAaaSConfig.port)
|
||||
.option(ChannelOption.TCP_FASTOPEN, 32)
|
||||
VIAaaSConfig.bindAddresses.forEach {
|
||||
chFutures.add(serverBootstrap.bind(it.host, it.port))
|
||||
}
|
||||
|
||||
ktorServer = embeddedServer(Netty, commandLineEnvironment(args)) {}.start(false)
|
||||
|
||||
viaaasLogger.info("Using compression: ${Natives.compress.loadedVariant}, crypto: ${Natives.cipher.loadedVariant}")
|
||||
viaaasLogger.info("Binded minecraft into " + chFuture!!.sync().channel().localAddress())
|
||||
viaaasLogger.info(
|
||||
"Using compression: {}, crypto: {}",
|
||||
Natives.compress.loadedVariant,
|
||||
Natives.cipher.loadedVariant
|
||||
)
|
||||
chFutures.forEach {
|
||||
viaaasLogger.info("Binded minecraft into {}", it.sync().channel().localAddress())
|
||||
}
|
||||
viaaasLogger.info(
|
||||
"Application started in " + ManagementFactory.getRuntimeMXBean().uptime
|
||||
.milliseconds.toDouble(DurationUnit.SECONDS) + "s"
|
||||
)
|
||||
}
|
||||
|
||||
fun generateCert() {
|
||||
File("config/https.jks").apply {
|
||||
parentFile.mkdirs()
|
||||
if (!exists()) generateCertificate(this)
|
||||
if (!exists()) generateCertificate(this, keySizeInBits = 4096, algorithm = "SHA384withRSA")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,13 +156,13 @@ object AspirinServer {
|
|||
}
|
||||
|
||||
fun currentPlayers(): Int {
|
||||
return Via.getManager().connectionManager.connections.filter { it.protocolInfo.state == State.PLAY }.count()
|
||||
return Via.getManager().connectionManager.connections.filter { it.protocolInfo.serverState == State.PLAY }.count()
|
||||
}
|
||||
|
||||
suspend fun updaterCheckMessage(): String {
|
||||
return try {
|
||||
val latestData =
|
||||
httpClient.get<JsonObject>("https://api.github.com/repos/viaversion/viaaas/releases/latest")
|
||||
val latestData = httpClient.get("https://api.github.com/repos/viaversion/viaaas/releases/latest")
|
||||
.body<JsonObject>()
|
||||
val latest = Version(latestData["tag_name"]!!.asString.removePrefix("v"))
|
||||
val current = Version(cleanedVer)
|
||||
when {
|
||||
|
|
|
@ -7,9 +7,10 @@ import com.google.common.primitives.Ints
|
|||
import com.google.gson.JsonObject
|
||||
import com.viaversion.aas.config.VIAaaSConfig
|
||||
import com.viaversion.aas.util.StacklessException
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion
|
||||
import com.viaversion.viaversion.api.type.Type
|
||||
import com.viaversion.viaversion.api.type.Types
|
||||
import io.ktor.client.call.body
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.netty.*
|
||||
import io.netty.buffer.ByteBuf
|
||||
import io.netty.channel.Channel
|
||||
|
@ -43,6 +44,7 @@ import java.security.PublicKey
|
|||
import java.security.SecureRandom
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.logging.Logger
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
|
@ -50,6 +52,7 @@ val badLength = DecoderException("Invalid length!")
|
|||
val mcLogger = LoggerFactory.getLogger("VIAaaS MC")
|
||||
val webLogger = LoggerFactory.getLogger("VIAaaS Web")
|
||||
val viaaasLogger = LoggerFactory.getLogger("VIAaaS")
|
||||
val viaaasLoggerJava = Logger.getLogger("VIAaaS")
|
||||
|
||||
val secureRandom = SecureRandom()
|
||||
|
||||
|
@ -82,12 +85,13 @@ suspend fun resolveSrv(hostAndPort: HostAndPort): HostAndPort {
|
|||
return hostAndPort
|
||||
}
|
||||
|
||||
fun decryptRsa(privateKey: PrivateKey, data: ByteArray) = Cipher.getInstance("RSA").let {
|
||||
// https://medium.com/asecuritysite-when-bob-met-alice/whats-so-special-about-pkcs-1-v1-5-and-the-attack-that-just-won-t-go-away-51ccf35d65b7
|
||||
fun decryptRsa(privateKey: PrivateKey, data: ByteArray) = Cipher.getInstance("RSA/ECB/PKCS1Padding").let {
|
||||
it.init(Cipher.DECRYPT_MODE, privateKey)
|
||||
it.doFinal(data)
|
||||
}
|
||||
|
||||
fun encryptRsa(publicKey: PublicKey, data: ByteArray) = Cipher.getInstance("RSA").let {
|
||||
fun encryptRsa(publicKey: PublicKey, data: ByteArray) = Cipher.getInstance("RSA/ECB/PKCS1Padding").let {
|
||||
it.init(Cipher.ENCRYPT_MODE, publicKey)
|
||||
it.doFinal(data)
|
||||
}
|
||||
|
@ -184,15 +188,17 @@ fun writeFlushClose(ch: Channel, obj: Any, delay: Boolean = false) {
|
|||
}
|
||||
}
|
||||
|
||||
fun readRemainingBytes(byteBuf: ByteBuf) = Type.REMAINING_BYTES.read(byteBuf)!!
|
||||
fun readRemainingBytes(byteBuf: ByteBuf) = Types.REMAINING_BYTES.read(byteBuf)!!
|
||||
fun ByteBuf.readByteArray(length: Int) = ByteArray(length).also { readBytes(it) }
|
||||
|
||||
suspend fun hasJoined(username: String, hash: String): JsonObject {
|
||||
return try {
|
||||
AspirinServer.httpClient.get(
|
||||
try {
|
||||
val req = AspirinServer.httpClient.get(
|
||||
"https://sessionserver.mojang.com/session/minecraft/hasJoined?username=" +
|
||||
UrlEscapers.urlFormParameterEscaper().escape(username) + "&serverId=$hash"
|
||||
)
|
||||
if (!req.status.isSuccess() || req.status == HttpStatusCode.NoContent) throw StacklessException("http code ${req.status}")
|
||||
return req.body()
|
||||
} catch (e: Exception) {
|
||||
throw StacklessException("Couldn't authenticate with session servers", e)
|
||||
}
|
||||
|
@ -205,8 +211,6 @@ fun generateServerId() = ByteArray(13).let {
|
|||
// https://developer.mozilla.org/en-US/docs/Glossary/Base64 133% of original
|
||||
}
|
||||
|
||||
fun Int.parseProtocol() = ProtocolVersion.getProtocol(this)
|
||||
|
||||
fun sha512Hex(data: ByteArray): String {
|
||||
return MessageDigest.getInstance("SHA-512").digest(data)
|
||||
.asUByteArray()
|
||||
|
|
|
@ -1,29 +1,30 @@
|
|||
package com.viaversion.aas
|
||||
|
||||
import com.viaversion.aas.command.VIAaaSConsole
|
||||
import com.viaversion.aas.command.ViaAspirinCommand
|
||||
import com.viaversion.aas.platform.*
|
||||
import com.viaversion.aas.config.VIAaaSConfig
|
||||
import com.viaversion.aas.platform.AspirinAprilFools
|
||||
import com.viaversion.aas.platform.AspirinBackwards
|
||||
import com.viaversion.aas.platform.AspirinLegacy
|
||||
import com.viaversion.aas.platform.AspirinPlatform
|
||||
import com.viaversion.aas.platform.AspirinRewind
|
||||
import com.viaversion.aas.protocol.registerAspirinProtocols
|
||||
import com.viaversion.aas.web.ViaWebApp
|
||||
import com.viaversion.viaversion.ViaManagerImpl
|
||||
import com.viaversion.viaversion.api.Via
|
||||
import com.viaversion.viaversion.api.data.MappingDataLoader
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion
|
||||
import de.gerrygames.viarewind.api.ViaRewindConfigImpl
|
||||
import io.ktor.application.*
|
||||
import com.viaversion.viaversion.api.protocol.version.VersionType
|
||||
import io.ktor.server.application.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import org.apache.logging.log4j.Level
|
||||
import org.apache.logging.log4j.io.IoBuilder
|
||||
import java.io.File
|
||||
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
try {
|
||||
setupSystem()
|
||||
printSplash()
|
||||
CoroutineScope(Dispatchers.IO).launch { viaaasLogger.info(AspirinServer.updaterCheckMessage()) }
|
||||
CoroutineScope(Job()).launch { viaaasLogger.info("{}", AspirinServer.updaterCheckMessage()) }
|
||||
AspirinServer.generateCert()
|
||||
initVia()
|
||||
AspirinServer.listenPorts(args)
|
||||
|
@ -34,7 +35,7 @@ fun main(args: Array<String>) {
|
|||
Thread { VIAaaSConsole.start() }.start()
|
||||
|
||||
AspirinServer.waitStopSignal()
|
||||
} catch (e: Exception) {
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
AspirinServer.finish()
|
||||
|
@ -42,10 +43,6 @@ fun main(args: Array<String>) {
|
|||
}
|
||||
|
||||
private fun setupSystem() {
|
||||
// Stolen from https://github.com/VelocityPowered/Velocity/blob/dev/1.1.0/proxy/src/main/java/com/velocitypowered/proxy/Velocity.java
|
||||
if (System.getProperty("io.netty.allocator.maxOrder") == null) {
|
||||
System.setProperty("io.netty.allocator.maxOrder", "9")
|
||||
}
|
||||
// https://logging.apache.org/log4j/2.x/log4j-jul/index.html
|
||||
if (System.getProperty("java.util.logging.manager") == null) {
|
||||
System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager")
|
||||
|
@ -56,29 +53,21 @@ private fun setupSystem() {
|
|||
}
|
||||
|
||||
private fun printSplash() {
|
||||
println(
|
||||
"""\\ // // //\\ => //|| //|| /=====/ PROXY
|
||||
| \\ // // // \\ // || // || //
|
||||
| \\ // // //====\\ //==|| //==|| \====\ ${AspirinServer.version}
|
||||
| \\ // // // \\ // || // || //
|
||||
|<= \\// // // \\ // || // || /====/""".trimMargin()
|
||||
)
|
||||
println("VIAaaS ${AspirinServer.version}")
|
||||
}
|
||||
|
||||
private fun initVia() {
|
||||
Via.init(
|
||||
ViaManagerImpl.builder()
|
||||
.injector(AspirinInjector())
|
||||
.loader(AspirinLoader())
|
||||
.commandHandler(ViaAspirinCommand)
|
||||
.platform(AspirinPlatform).build()
|
||||
)
|
||||
MappingDataLoader.enableMappingsCache()
|
||||
(Via.getManager() as ViaManagerImpl).init()
|
||||
AspirinRewind().init(ViaRewindConfigImpl(File("config/viarewind.yml")))
|
||||
AspirinBackwards().init(File("config/viabackwards"))
|
||||
val AUTO = ProtocolVersion(VersionType.SPECIAL, -2, -1, "AUTO", null)
|
||||
|
||||
ProtocolVersion.register(-2, "AUTO")
|
||||
private fun initVia() {
|
||||
AspirinPlatform.initVia {
|
||||
AspirinRewind().init()
|
||||
AspirinBackwards().init()
|
||||
AspirinAprilFools().init()
|
||||
AspirinLegacy().init()
|
||||
Via.getManager().configurationProvider.register(VIAaaSConfig)
|
||||
}
|
||||
|
||||
ProtocolVersion.register(AUTO)
|
||||
registerAspirinProtocols()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
package com.viaversion.aas.codec
|
||||
|
||||
import com.viaversion.aas.badLength
|
||||
import com.viaversion.viaversion.api.type.Type
|
||||
import com.viaversion.viaversion.exception.CancelDecoderException
|
||||
import io.netty.buffer.ByteBuf
|
||||
import io.netty.channel.ChannelHandlerContext
|
||||
import io.netty.handler.codec.ByteToMessageCodec
|
||||
|
||||
class FrameCodec : ByteToMessageCodec<ByteBuf>() {
|
||||
override fun decode(ctx: ChannelHandlerContext, input: ByteBuf, out: MutableList<Any>) {
|
||||
if (!ctx.channel().isActive) {
|
||||
input.clear()
|
||||
// Netty throws an exception when there's no output
|
||||
throw CancelDecoderException.CACHED
|
||||
}
|
||||
// Ignore, should prevent DoS https://github.com/SpigotMC/BungeeCord/pull/2908
|
||||
|
||||
val index = input.readerIndex()
|
||||
var nByte = 0
|
||||
val result = input.forEachByte {
|
||||
nByte++
|
||||
val hasNext = it.toInt().and(0x10000000) != 0
|
||||
if (nByte > 3) throw badLength
|
||||
hasNext
|
||||
}
|
||||
input.readerIndex(index)
|
||||
if (result == -1) return // not readable
|
||||
|
||||
val length = Type.VAR_INT.readPrimitive(input)
|
||||
|
||||
if (length >= 2097152 || length < 0) throw badLength
|
||||
if (!input.isReadable(length)) {
|
||||
input.readerIndex(index)
|
||||
return
|
||||
}
|
||||
|
||||
out.add(input.readRetainedSlice(length))
|
||||
}
|
||||
|
||||
override fun encode(ctx: ChannelHandlerContext, msg: ByteBuf, out: ByteBuf) {
|
||||
if (msg.readableBytes() >= 2097152) throw badLength
|
||||
Type.VAR_INT.writePrimitive(out, msg.readableBytes())
|
||||
out.writeBytes(msg)
|
||||
}
|
||||
}
|
|
@ -1,34 +1,56 @@
|
|||
package com.viaversion.aas.codec.packet
|
||||
|
||||
import com.google.common.collect.Range
|
||||
import com.google.common.collect.RangeMap
|
||||
import com.google.common.collect.TreeRangeMap
|
||||
import com.viaversion.aas.codec.packet.configuration.*
|
||||
import com.viaversion.aas.codec.packet.handshake.Handshake
|
||||
import com.viaversion.aas.codec.packet.login.*
|
||||
import com.viaversion.aas.codec.packet.play.Kick
|
||||
import com.viaversion.aas.codec.packet.play.PluginMessage
|
||||
import com.viaversion.aas.codec.packet.play.SetPlayCompression
|
||||
import com.viaversion.aas.codec.packet.play.*
|
||||
import com.viaversion.aas.codec.packet.status.StatusPing
|
||||
import com.viaversion.aas.codec.packet.status.StatusPong
|
||||
import com.viaversion.aas.codec.packet.status.StatusRequest
|
||||
import com.viaversion.aas.codec.packet.status.StatusResponse
|
||||
import com.viaversion.aas.util.StacklessException
|
||||
import com.viaversion.viaversion.api.protocol.packet.Direction
|
||||
import com.viaversion.viaversion.api.protocol.packet.State
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion
|
||||
import com.viaversion.viaversion.api.type.Type
|
||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ClientboundPackets1_13
|
||||
import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.ClientboundPackets1_14
|
||||
import com.viaversion.viaversion.protocols.protocol1_15to1_14_4.ClientboundPackets1_15
|
||||
import com.viaversion.viaversion.protocols.protocol1_16_2to1_16_1.ClientboundPackets1_16_2
|
||||
import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.ClientboundPackets1_16
|
||||
import com.viaversion.viaversion.protocols.protocol1_17to1_16_4.ClientboundPackets1_17
|
||||
import com.viaversion.viaversion.protocols.protocol1_8.ClientboundPackets1_8
|
||||
import com.viaversion.viaversion.protocols.protocol1_9to1_8.ClientboundPackets1_9
|
||||
import com.viaversion.viaversion.api.type.Types
|
||||
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13
|
||||
import com.viaversion.viaversion.protocols.v1_13_2to1_14.packet.ClientboundPackets1_14
|
||||
import com.viaversion.viaversion.protocols.v1_14_4to1_15.packet.ClientboundPackets1_15
|
||||
import com.viaversion.viaversion.protocols.v1_15_2to1_16.packet.ClientboundPackets1_16
|
||||
import com.viaversion.viaversion.protocols.v1_16_1to1_16_2.packet.ClientboundPackets1_16_2
|
||||
import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ClientboundPackets1_17
|
||||
import com.viaversion.viaversion.protocols.v1_17_1to1_18.packet.ClientboundPackets1_18
|
||||
import com.viaversion.viaversion.protocols.v1_18_2to1_19.packet.ClientboundPackets1_19
|
||||
import com.viaversion.viaversion.protocols.v1_18_2to1_19.packet.ServerboundPackets1_19
|
||||
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.packet.ClientboundPackets1_19_3
|
||||
import com.viaversion.viaversion.protocols.v1_19_3to1_19_4.packet.ClientboundPackets1_19_4
|
||||
import com.viaversion.viaversion.protocols.v1_19to1_19_1.packet.ClientboundPackets1_19_1
|
||||
import com.viaversion.viaversion.protocols.v1_19to1_19_1.packet.ServerboundPackets1_19_1
|
||||
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundConfigurationPackets1_20_5
|
||||
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundPackets1_20_5
|
||||
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundConfigurationPackets1_20_5
|
||||
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPackets1_20_5
|
||||
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ClientboundConfigurationPackets1_20_2
|
||||
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ClientboundPackets1_20_2
|
||||
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ServerboundConfigurationPackets1_20_2
|
||||
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ServerboundPackets1_20_2
|
||||
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_8
|
||||
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_9
|
||||
import io.netty.buffer.ByteBuf
|
||||
import io.netty.buffer.ByteBufAllocator
|
||||
import io.netty.util.ReferenceCountUtil
|
||||
import java.util.function.Supplier
|
||||
|
||||
object PacketRegistry {
|
||||
val entries = mutableListOf<RegistryEntry>()
|
||||
// state, direction, packet id, protocol version -> entry
|
||||
private val entriesDecoding = hashMapOf<Triple<State, Direction, Int>, RangeMap<ProtocolVersion, DecodingInfo>>()
|
||||
|
||||
// direction, type, protocol version -> entry
|
||||
private val entriesEncoding =
|
||||
hashMapOf<Pair<Direction, Class<out Packet>>, RangeMap<ProtocolVersion, EncodingInfo>>()
|
||||
|
||||
init {
|
||||
// Obviously stolen from https://github.com/VelocityPowered/Velocity/blob/dev/1.1.0/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java
|
||||
|
@ -36,127 +58,228 @@ object PacketRegistry {
|
|||
|
||||
register(State.LOGIN, Direction.SERVERBOUND, ::LoginStart, Range.all(), 0)
|
||||
register(State.LOGIN, Direction.SERVERBOUND, ::CryptoResponse, Range.all(), 1)
|
||||
register(State.LOGIN, Direction.SERVERBOUND, ::PluginResponse, Range.atLeast(ProtocolVersion.v1_13.version), 2)
|
||||
register(State.LOGIN, Direction.SERVERBOUND, ::PluginResponse, Range.atLeast(ProtocolVersion.v1_13), 2)
|
||||
register(State.LOGIN, Direction.SERVERBOUND, ::LoginAck, Range.atLeast(ProtocolVersion.v1_20_2), 3)
|
||||
register(State.LOGIN, Direction.SERVERBOUND, ::LoginCookieResponse, Range.atLeast(ProtocolVersion.v1_20_5), 4)
|
||||
|
||||
register(State.LOGIN, Direction.CLIENTBOUND, ::LoginDisconnect, Range.all(), 0)
|
||||
register(State.LOGIN, Direction.CLIENTBOUND, ::CryptoRequest, Range.all(), 1)
|
||||
register(State.LOGIN, Direction.CLIENTBOUND, ::LoginSuccess, Range.all(), 2)
|
||||
register(State.LOGIN, Direction.CLIENTBOUND, ::SetCompression, Range.all(), 3)
|
||||
register(State.LOGIN, Direction.CLIENTBOUND, ::PluginRequest, Range.atLeast(ProtocolVersion.v1_13.version), 4)
|
||||
register(State.LOGIN, Direction.CLIENTBOUND, ::SetCompression, Range.atLeast(ProtocolVersion.v1_8), 3)
|
||||
register(State.LOGIN, Direction.CLIENTBOUND, ::PluginRequest, Range.atLeast(ProtocolVersion.v1_13), 4)
|
||||
register(State.LOGIN, Direction.CLIENTBOUND, ::LoginCookieRequest, Range.atLeast(ProtocolVersion.v1_20_5), 5)
|
||||
|
||||
register(State.STATUS, Direction.SERVERBOUND, ::StatusRequest, Range.all(), 0)
|
||||
register(State.STATUS, Direction.SERVERBOUND, ::StatusPing, Range.all(), 1)
|
||||
register(State.STATUS, Direction.CLIENTBOUND, ::StatusResponse, Range.all(), 0)
|
||||
register(State.STATUS, Direction.CLIENTBOUND, ::StatusPong, Range.all(), 1)
|
||||
|
||||
// Play
|
||||
register(
|
||||
State.CONFIGURATION, Direction.CLIENTBOUND, ::ConfigurationCookieRequest,
|
||||
Range.atLeast(ProtocolVersion.v1_20_5), ClientboundConfigurationPackets1_20_5.COOKIE_REQUEST.id
|
||||
)
|
||||
register(
|
||||
State.CONFIGURATION, Direction.CLIENTBOUND, ::ConfigurationPluginMessage, mapOf(
|
||||
ProtocolVersion.v1_20_2..ProtocolVersion.v1_20_3 to ClientboundConfigurationPackets1_20_2.CUSTOM_PAYLOAD.id,
|
||||
Range.atLeast(ProtocolVersion.v1_20_5) to ClientboundConfigurationPackets1_20_5.CUSTOM_PAYLOAD.id
|
||||
)
|
||||
)
|
||||
register(
|
||||
State.CONFIGURATION, Direction.CLIENTBOUND, ::ConfigurationDisconnect, mapOf(
|
||||
ProtocolVersion.v1_20_2..ProtocolVersion.v1_20_3 to ClientboundConfigurationPackets1_20_2.DISCONNECT.id,
|
||||
Range.atLeast(ProtocolVersion.v1_20_5) to ClientboundConfigurationPackets1_20_5.DISCONNECT.id
|
||||
)
|
||||
)
|
||||
register(
|
||||
State.CONFIGURATION, Direction.CLIENTBOUND, ::FinishConfig, mapOf(
|
||||
ProtocolVersion.v1_20_2..ProtocolVersion.v1_20_3 to ClientboundConfigurationPackets1_20_2.FINISH_CONFIGURATION.id,
|
||||
Range.atLeast(ProtocolVersion.v1_20_5) to ClientboundConfigurationPackets1_20_5.FINISH_CONFIGURATION.id
|
||||
)
|
||||
)
|
||||
register(
|
||||
State.CONFIGURATION, Direction.CLIENTBOUND, ::ConfigurationKeepAlive, mapOf(
|
||||
ProtocolVersion.v1_20_2..ProtocolVersion.v1_20_3 to ClientboundConfigurationPackets1_20_2.KEEP_ALIVE.id,
|
||||
Range.atLeast(ProtocolVersion.v1_20_5) to ClientboundConfigurationPackets1_20_5.KEEP_ALIVE.id
|
||||
)
|
||||
)
|
||||
register(
|
||||
State.CONFIGURATION, Direction.CLIENTBOUND, ::ConfigurationTransfer,
|
||||
Range.atLeast(ProtocolVersion.v1_20_5), ClientboundConfigurationPackets1_20_5.TRANSFER.id
|
||||
)
|
||||
|
||||
register(
|
||||
State.CONFIGURATION, Direction.SERVERBOUND, ::ConfigurationCookieResponse,
|
||||
Range.atLeast(ProtocolVersion.v1_20_5), ServerboundConfigurationPackets1_20_5.COOKIE_RESPONSE.id
|
||||
)
|
||||
register(
|
||||
State.CONFIGURATION, Direction.SERVERBOUND, ::ConfigurationPluginMessage, mapOf(
|
||||
ProtocolVersion.v1_20_2..ProtocolVersion.v1_20_3 to ServerboundConfigurationPackets1_20_2.CUSTOM_PAYLOAD.id,
|
||||
Range.atLeast(ProtocolVersion.v1_20_5) to ServerboundConfigurationPackets1_20_5.CUSTOM_PAYLOAD.id
|
||||
)
|
||||
)
|
||||
register(
|
||||
State.CONFIGURATION, Direction.SERVERBOUND, ::FinishConfig, mapOf(
|
||||
ProtocolVersion.v1_20_2..ProtocolVersion.v1_20_3 to ServerboundConfigurationPackets1_20_2.FINISH_CONFIGURATION.id,
|
||||
Range.atLeast(ProtocolVersion.v1_20_5) to ServerboundConfigurationPackets1_20_5.FINISH_CONFIGURATION.id
|
||||
)
|
||||
)
|
||||
register(
|
||||
State.CONFIGURATION, Direction.SERVERBOUND, ::ConfigurationKeepAlive, mapOf(
|
||||
ProtocolVersion.v1_20_2..ProtocolVersion.v1_20_3 to ServerboundConfigurationPackets1_20_2.KEEP_ALIVE.id,
|
||||
Range.atLeast(ProtocolVersion.v1_20_5) to ServerboundConfigurationPackets1_20_5.KEEP_ALIVE.id
|
||||
)
|
||||
)
|
||||
|
||||
register(
|
||||
State.PLAY, Direction.CLIENTBOUND, ::Kick, mapOf(
|
||||
ProtocolVersion.v1_7_1..ProtocolVersion.v1_8 to ClientboundPackets1_8.DISCONNECT.id,
|
||||
ProtocolVersion.v1_7_2..ProtocolVersion.v1_8 to ClientboundPackets1_8.DISCONNECT.id,
|
||||
ProtocolVersion.v1_9..ProtocolVersion.v1_12_2 to ClientboundPackets1_9.DISCONNECT.id,
|
||||
ProtocolVersion.v1_13..ProtocolVersion.v1_13_2 to ClientboundPackets1_13.DISCONNECT.id,
|
||||
ProtocolVersion.v1_14..ProtocolVersion.v1_14_4 to ClientboundPackets1_14.DISCONNECT.id,
|
||||
ProtocolVersion.v1_15..ProtocolVersion.v1_15_2 to ClientboundPackets1_15.DISCONNECT.id,
|
||||
ProtocolVersion.v1_16..ProtocolVersion.v1_16_1 to ClientboundPackets1_16.DISCONNECT.id,
|
||||
ProtocolVersion.v1_16_2..ProtocolVersion.v1_16_4 to ClientboundPackets1_16_2.DISCONNECT.id,
|
||||
ProtocolVersion.v1_17..ProtocolVersion.v1_17_1 to ClientboundPackets1_17.DISCONNECT.id
|
||||
ProtocolVersion.v1_17..ProtocolVersion.v1_17_1 to ClientboundPackets1_17.DISCONNECT.id,
|
||||
ProtocolVersion.v1_18..ProtocolVersion.v1_18_2 to ClientboundPackets1_18.DISCONNECT.id,
|
||||
ProtocolVersion.v1_19.singleton to ClientboundPackets1_19.DISCONNECT.id,
|
||||
ProtocolVersion.v1_19_1.singleton to ClientboundPackets1_19_1.DISCONNECT.id,
|
||||
ProtocolVersion.v1_19_3.singleton to ClientboundPackets1_19_3.DISCONNECT.id,
|
||||
ProtocolVersion.v1_19_4..ProtocolVersion.v1_20 to ClientboundPackets1_19_4.DISCONNECT.id,
|
||||
ProtocolVersion.v1_20_2..ProtocolVersion.v1_20_3 to ClientboundPackets1_20_2.DISCONNECT.id,
|
||||
ProtocolVersion.v1_20_5..ProtocolVersion.v1_21 to ClientboundPackets1_20_5.DISCONNECT.id
|
||||
)
|
||||
)
|
||||
|
||||
register(
|
||||
State.PLAY, Direction.CLIENTBOUND, ::PluginMessage, mapOf(
|
||||
ProtocolVersion.v1_7_1..ProtocolVersion.v1_8 to ClientboundPackets1_8.PLUGIN_MESSAGE.id,
|
||||
ProtocolVersion.v1_9..ProtocolVersion.v1_12_2 to ClientboundPackets1_9.PLUGIN_MESSAGE.id,
|
||||
ProtocolVersion.v1_13..ProtocolVersion.v1_13_2 to ClientboundPackets1_13.PLUGIN_MESSAGE.id,
|
||||
ProtocolVersion.v1_14..ProtocolVersion.v1_14_4 to ClientboundPackets1_14.PLUGIN_MESSAGE.id,
|
||||
ProtocolVersion.v1_15..ProtocolVersion.v1_15_2 to ClientboundPackets1_15.PLUGIN_MESSAGE.id,
|
||||
ProtocolVersion.v1_16..ProtocolVersion.v1_16_1 to ClientboundPackets1_16.PLUGIN_MESSAGE.id,
|
||||
ProtocolVersion.v1_16_2..ProtocolVersion.v1_16_4 to ClientboundPackets1_16_2.PLUGIN_MESSAGE.id,
|
||||
ProtocolVersion.v1_17..ProtocolVersion.v1_17_1 to ClientboundPackets1_17.PLUGIN_MESSAGE.id
|
||||
ProtocolVersion.v1_7_2..ProtocolVersion.v1_8 to ClientboundPackets1_8.CUSTOM_PAYLOAD.id,
|
||||
ProtocolVersion.v1_9..ProtocolVersion.v1_12_2 to ClientboundPackets1_9.CUSTOM_PAYLOAD.id,
|
||||
ProtocolVersion.v1_13..ProtocolVersion.v1_13_2 to ClientboundPackets1_13.CUSTOM_PAYLOAD.id,
|
||||
ProtocolVersion.v1_14..ProtocolVersion.v1_14_4 to ClientboundPackets1_14.CUSTOM_PAYLOAD.id,
|
||||
ProtocolVersion.v1_15..ProtocolVersion.v1_15_2 to ClientboundPackets1_15.CUSTOM_PAYLOAD.id,
|
||||
ProtocolVersion.v1_16..ProtocolVersion.v1_16_1 to ClientboundPackets1_16.CUSTOM_PAYLOAD.id,
|
||||
ProtocolVersion.v1_16_2..ProtocolVersion.v1_16_4 to ClientboundPackets1_16_2.CUSTOM_PAYLOAD.id,
|
||||
ProtocolVersion.v1_17..ProtocolVersion.v1_17_1 to ClientboundPackets1_17.CUSTOM_PAYLOAD.id,
|
||||
ProtocolVersion.v1_18..ProtocolVersion.v1_18_2 to ClientboundPackets1_18.CUSTOM_PAYLOAD.id,
|
||||
ProtocolVersion.v1_19.singleton to ClientboundPackets1_19.CUSTOM_PAYLOAD.id,
|
||||
ProtocolVersion.v1_19_1.singleton to ClientboundPackets1_19_1.CUSTOM_PAYLOAD.id,
|
||||
ProtocolVersion.v1_19_3.singleton to ClientboundPackets1_19_3.CUSTOM_PAYLOAD.id,
|
||||
ProtocolVersion.v1_19_4..ProtocolVersion.v1_20 to ClientboundPackets1_19_4.CUSTOM_PAYLOAD.id,
|
||||
ProtocolVersion.v1_20_2..ProtocolVersion.v1_20_3 to ClientboundPackets1_20_2.CUSTOM_PAYLOAD.id,
|
||||
ProtocolVersion.v1_20_5..ProtocolVersion.v1_21 to ClientboundPackets1_20_5.CUSTOM_PAYLOAD.id
|
||||
)
|
||||
)
|
||||
|
||||
register(
|
||||
State.PLAY,
|
||||
Direction.CLIENTBOUND,
|
||||
::SetPlayCompression,
|
||||
ProtocolVersion.v1_8.singleton,
|
||||
ClientboundPackets1_8.SET_COMPRESSION.id
|
||||
State.PLAY, Direction.CLIENTBOUND, ::SetPlayCompression,
|
||||
ProtocolVersion.v1_8.singleton, ClientboundPackets1_8.SET_COMPRESSION.id
|
||||
)
|
||||
register(
|
||||
State.PLAY, Direction.SERVERBOUND, ::ConfigurationAck, mapOf(
|
||||
ProtocolVersion.v1_20_2..ProtocolVersion.v1_20_3 to ServerboundPackets1_20_2.CONFIGURATION_ACKNOWLEDGED.id,
|
||||
ProtocolVersion.v1_20_5..ProtocolVersion.v1_21 to ServerboundPackets1_20_5.CONFIGURATION_ACKNOWLEDGED.id
|
||||
)
|
||||
)
|
||||
// todo update chat to latest version
|
||||
// todo handle transfer packets
|
||||
register(
|
||||
State.PLAY, Direction.SERVERBOUND, ::ServerboundChatCommand,
|
||||
mapOf(
|
||||
ProtocolVersion.v1_19.singleton to ServerboundPackets1_19.CHAT_COMMAND.id,
|
||||
ProtocolVersion.v1_19_1.singleton to ServerboundPackets1_19_1.CHAT_COMMAND.id
|
||||
)
|
||||
)
|
||||
register(
|
||||
State.PLAY, Direction.SERVERBOUND, ::ServerboundChatMessage,
|
||||
mapOf(
|
||||
ProtocolVersion.v1_19.singleton to ServerboundPackets1_19.CHAT.id,
|
||||
ProtocolVersion.v1_19_1.singleton to ServerboundPackets1_19_1.CHAT.id
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
operator fun ProtocolVersion.rangeTo(o: ProtocolVersion): Range<Int> {
|
||||
return Range.closed(this.originalVersion, o.originalVersion)
|
||||
operator fun ProtocolVersion.rangeTo(o: ProtocolVersion): Range<ProtocolVersion> {
|
||||
return Range.closed(this, o)
|
||||
}
|
||||
|
||||
val ProtocolVersion.singleton get() = Range.singleton(this.originalVersion)
|
||||
private val ProtocolVersion.singleton get() = Range.singleton(this)
|
||||
|
||||
inline fun <reified P : Packet> register(
|
||||
state: State,
|
||||
direction: Direction,
|
||||
private inline fun <reified P : Packet> register(
|
||||
state: State, direction: Direction,
|
||||
constructor: Supplier<P>,
|
||||
idByProtocol: Map<Range<Int>, Int>,
|
||||
idByProtocol: Map<Range<ProtocolVersion>, Int>,
|
||||
klass: Class<P> = P::class.java,
|
||||
) {
|
||||
entries.add(RegistryEntry(idByProtocol, state, direction, constructor, klass))
|
||||
idByProtocol.forEach { (protocolRange, packetId) ->
|
||||
entriesDecoding.computeIfAbsent(Triple(state, direction, packetId)) { TreeRangeMap.create() }
|
||||
.also { rangeMap ->
|
||||
if (rangeMap.subRangeMap(protocolRange).asMapOfRanges().isNotEmpty())
|
||||
throw IllegalStateException("entry already exists")
|
||||
rangeMap.put(protocolRange, DecodingInfo(constructor))
|
||||
}
|
||||
}
|
||||
|
||||
val protocolRangeToId = TreeRangeMap.create<ProtocolVersion, Int>()
|
||||
idByProtocol.forEach { (range, id) -> protocolRangeToId.put(range, id) }
|
||||
|
||||
entriesEncoding.computeIfAbsent(direction to klass) { TreeRangeMap.create() }.also { rangeMap ->
|
||||
idByProtocol.forEach { (protocolRange, packetId) ->
|
||||
if (rangeMap.subRangeMap(protocolRange).asMapOfRanges().isNotEmpty())
|
||||
throw IllegalStateException("entry already exists")
|
||||
rangeMap.put(protocolRange, EncodingInfo(packetId))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified P : Packet> register(
|
||||
state: State,
|
||||
direction: Direction,
|
||||
private inline fun <reified P : Packet> register(
|
||||
state: State, direction: Direction,
|
||||
constructor: Supplier<P>,
|
||||
protocol: Range<Int>,
|
||||
id: Int
|
||||
protocol: Range<ProtocolVersion>, id: Int
|
||||
) {
|
||||
register(constructor = constructor, direction = direction, state = state, idByProtocol = mapOf(protocol to id))
|
||||
}
|
||||
|
||||
data class RegistryEntry(
|
||||
val idByVersion: Map<Range<Int>, Int>,
|
||||
val state: State,
|
||||
val direction: Direction,
|
||||
val constructor: Supplier<out Packet>,
|
||||
val packetClass: Class<out Packet>
|
||||
)
|
||||
data class DecodingInfo(val constructor: Supplier<out Packet>)
|
||||
data class EncodingInfo(val packetId: Int)
|
||||
|
||||
fun getPacketConstructor(
|
||||
protocolVersion: Int,
|
||||
state: State,
|
||||
id: Int,
|
||||
direction: Direction
|
||||
private fun getPacketConstructor(
|
||||
protocolVersion: ProtocolVersion, state: State,
|
||||
id: Int, direction: Direction
|
||||
): Supplier<out Packet>? {
|
||||
return entries.firstOrNull {
|
||||
it.direction == direction
|
||||
&& it.state == state
|
||||
&& it.idByVersion.entries.firstOrNull { it.key.contains(protocolVersion) }?.value == id
|
||||
}?.constructor
|
||||
return entriesDecoding[Triple(state, direction, id)]?.get(protocolVersion)?.constructor
|
||||
}
|
||||
|
||||
fun getPacketId(packetClass: Class<out Packet>, protocolVersion: Int, direction: Direction): Int? {
|
||||
return entries.firstOrNull {
|
||||
it.packetClass == packetClass && it.direction == direction
|
||||
}?.idByVersion?.entries?.firstOrNull { it.key.contains(protocolVersion) }?.value
|
||||
private fun getPacketId(
|
||||
packetClass: Class<out Packet>,
|
||||
protocolVersion: ProtocolVersion, direction: Direction
|
||||
): Int? {
|
||||
return entriesEncoding[direction to packetClass]?.get(protocolVersion)?.packetId
|
||||
}
|
||||
|
||||
fun decode(byteBuf: ByteBuf, protocolVersion: Int, state: State, direction: Direction): Packet {
|
||||
val packetId = Type.VAR_INT.readPrimitive(byteBuf)
|
||||
fun decode(byteBuf: ByteBuf, protocolVersion: ProtocolVersion, state: State, direction: Direction): Packet {
|
||||
val packetId = Types.VAR_INT.readPrimitive(byteBuf)
|
||||
val packet = getPacketConstructor(protocolVersion, state, packetId, direction)?.get()
|
||||
?: UnknownPacket(packetId, ByteBufAllocator.DEFAULT.buffer())
|
||||
try {
|
||||
packet.decode(byteBuf, protocolVersion)
|
||||
return ReferenceCountUtil.retain(packet)
|
||||
} catch (e: Exception) {
|
||||
throw StacklessException("Failed to decode $packetId $state $direction", e)
|
||||
} finally {
|
||||
ReferenceCountUtil.release(packet)
|
||||
}
|
||||
}
|
||||
|
||||
fun encode(packet: Packet, byteBuf: ByteBuf, protocolVersion: Int, direction: Direction) {
|
||||
fun encode(packet: Packet, byteBuf: ByteBuf, protocolVersion: ProtocolVersion, direction: Direction) {
|
||||
val id = if (packet is UnknownPacket) {
|
||||
packet.id
|
||||
} else {
|
||||
getPacketId(packet.javaClass, protocolVersion, direction)!!
|
||||
getPacketId(packet.javaClass, protocolVersion, direction)
|
||||
?: throw StacklessException("Failed to get id for " + packet::class.java.simpleName)
|
||||
}
|
||||
Types.VAR_INT.writePrimitive(byteBuf, id)
|
||||
try {
|
||||
packet.encode(byteBuf, protocolVersion)
|
||||
} catch (e: Exception) {
|
||||
throw StacklessException("Failed to encode $id $direction", e)
|
||||
}
|
||||
Type.VAR_INT.writePrimitive(byteBuf, id)
|
||||
packet.encode(byteBuf, protocolVersion)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
package com.viaversion.aas.codec.packet
|
||||
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion
|
||||
import io.netty.buffer.ByteBuf
|
||||
import io.netty.buffer.ByteBufHolder
|
||||
|
||||
class UnknownPacket(val id: Int, val content: ByteBuf) : Packet, ByteBufHolder {
|
||||
override fun decode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
class UnknownPacket(val id: Int, private val content: ByteBuf) : Packet, ByteBufHolder {
|
||||
override fun decode(byteBuf: ByteBuf, protocolVersion: ProtocolVersion) {
|
||||
content.writeBytes(byteBuf)
|
||||
}
|
||||
|
||||
override fun encode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
override fun encode(byteBuf: ByteBuf, protocolVersion: ProtocolVersion) {
|
||||
byteBuf.writeBytes(content)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
package com.viaversion.aas.codec.packet.handshake
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet
|
||||
import com.viaversion.viaversion.api.protocol.packet.State
|
||||
import com.viaversion.viaversion.api.type.Type
|
||||
import com.viaversion.viaversion.api.type.types.StringType
|
||||
import io.netty.buffer.ByteBuf
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
class Handshake : Packet {
|
||||
var protocolId by Delegates.notNull<Int>()
|
||||
lateinit var address: String
|
||||
var port by Delegates.notNull<Int>()
|
||||
lateinit var nextState: State
|
||||
|
||||
override fun decode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
protocolId = Type.VAR_INT.readPrimitive(byteBuf)
|
||||
address = StringType(255).read(byteBuf)
|
||||
port = byteBuf.readUnsignedShort()
|
||||
nextState = State.values()[Type.VAR_INT.readPrimitive(byteBuf)]
|
||||
}
|
||||
|
||||
override fun encode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
Type.VAR_INT.writePrimitive(byteBuf, protocolId)
|
||||
Type.STRING.write(byteBuf, address)
|
||||
byteBuf.writeShort(port)
|
||||
byteBuf.writeByte(nextState.ordinal) // var int is too small, fits in a byte
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
package com.viaversion.aas.codec.packet.login
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet
|
||||
import com.viaversion.aas.readByteArray
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion
|
||||
import com.viaversion.viaversion.api.type.Type
|
||||
import io.netty.buffer.ByteBuf
|
||||
import java.security.KeyFactory
|
||||
import java.security.PublicKey
|
||||
import java.security.spec.X509EncodedKeySpec
|
||||
|
||||
class CryptoRequest : Packet {
|
||||
lateinit var serverId: String
|
||||
lateinit var publicKey: PublicKey
|
||||
lateinit var token: ByteArray
|
||||
|
||||
override fun decode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
serverId = Type.STRING.read(byteBuf)
|
||||
if (protocolVersion >= ProtocolVersion.v1_8.version) {
|
||||
publicKey = KeyFactory.getInstance("RSA")
|
||||
.generatePublic(X509EncodedKeySpec(Type.BYTE_ARRAY_PRIMITIVE.read(byteBuf)))
|
||||
token = Type.BYTE_ARRAY_PRIMITIVE.read(byteBuf)
|
||||
} else {
|
||||
publicKey = KeyFactory.getInstance("RSA")
|
||||
.generatePublic(X509EncodedKeySpec(byteBuf.readByteArray(byteBuf.readUnsignedShort())))
|
||||
token = byteBuf.readByteArray(byteBuf.readUnsignedShort())
|
||||
}
|
||||
}
|
||||
|
||||
override fun encode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
Type.STRING.write(byteBuf, serverId)
|
||||
if (protocolVersion >= ProtocolVersion.v1_8.version) {
|
||||
Type.BYTE_ARRAY_PRIMITIVE.write(byteBuf, publicKey.encoded)
|
||||
Type.BYTE_ARRAY_PRIMITIVE.write(byteBuf, token)
|
||||
} else {
|
||||
val encodedKey = publicKey.encoded
|
||||
byteBuf.writeShort(encodedKey.size)
|
||||
byteBuf.writeBytes(encodedKey)
|
||||
byteBuf.writeShort(token.size)
|
||||
byteBuf.writeBytes(token)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,34 +1,69 @@
|
|||
package com.viaversion.aas.codec.packet.login
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet
|
||||
import com.viaversion.aas.protocol.sharewareVersion
|
||||
import com.viaversion.aas.readByteArray
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion
|
||||
import com.viaversion.viaversion.api.type.Type
|
||||
import com.viaversion.viaversion.api.type.Types
|
||||
import io.netty.buffer.ByteBuf
|
||||
|
||||
class CryptoResponse : Packet {
|
||||
lateinit var encryptedKey: ByteArray
|
||||
lateinit var encryptedToken: ByteArray
|
||||
var encryptedNonce: ByteArray? = null
|
||||
var salt: Long? = null
|
||||
var signature: ByteArray? = null
|
||||
|
||||
override fun decode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
if (protocolVersion >= ProtocolVersion.v1_8.version) {
|
||||
encryptedKey = Type.BYTE_ARRAY_PRIMITIVE.read(byteBuf)
|
||||
encryptedToken = Type.BYTE_ARRAY_PRIMITIVE.read(byteBuf)
|
||||
} else {
|
||||
encryptedKey = byteBuf.readByteArray(byteBuf.readUnsignedShort())
|
||||
encryptedToken = byteBuf.readByteArray(byteBuf.readUnsignedShort())
|
||||
override fun decode(byteBuf: ByteBuf, protocolVersion: ProtocolVersion) {
|
||||
when {
|
||||
protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_19)
|
||||
&& protocolVersion.olderThan(ProtocolVersion.v1_19_3) -> {
|
||||
encryptedKey = Types.BYTE_ARRAY_PRIMITIVE.read(byteBuf)
|
||||
if (byteBuf.readBoolean()) {
|
||||
encryptedNonce = Types.BYTE_ARRAY_PRIMITIVE.read(byteBuf)
|
||||
} else {
|
||||
salt = byteBuf.readLong()
|
||||
signature = Types.BYTE_ARRAY_PRIMITIVE.read(byteBuf)
|
||||
}
|
||||
}
|
||||
|
||||
protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_8) || protocolVersion.equalTo(sharewareVersion) -> {
|
||||
encryptedKey = Types.BYTE_ARRAY_PRIMITIVE.read(byteBuf)
|
||||
encryptedNonce = Types.BYTE_ARRAY_PRIMITIVE.read(byteBuf)
|
||||
}
|
||||
|
||||
else -> {
|
||||
encryptedKey = byteBuf.readByteArray(byteBuf.readUnsignedShort())
|
||||
encryptedNonce = byteBuf.readByteArray(byteBuf.readUnsignedShort())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun encode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
if (protocolVersion >= ProtocolVersion.v1_8.version) {
|
||||
Type.BYTE_ARRAY_PRIMITIVE.write(byteBuf, encryptedKey)
|
||||
Type.BYTE_ARRAY_PRIMITIVE.write(byteBuf, encryptedToken)
|
||||
} else {
|
||||
byteBuf.writeShort(encryptedKey.size)
|
||||
byteBuf.writeBytes(encryptedKey)
|
||||
byteBuf.writeShort(encryptedToken.size)
|
||||
byteBuf.writeBytes(encryptedToken)
|
||||
override fun encode(byteBuf: ByteBuf, protocolVersion: ProtocolVersion) {
|
||||
when {
|
||||
protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_19)
|
||||
&& protocolVersion.olderThan(ProtocolVersion.v1_19_3) -> {
|
||||
Types.BYTE_ARRAY_PRIMITIVE.write(byteBuf, encryptedKey)
|
||||
if (encryptedNonce != null) {
|
||||
byteBuf.writeBoolean(true)
|
||||
Types.BYTE_ARRAY_PRIMITIVE.write(byteBuf, encryptedNonce)
|
||||
} else {
|
||||
byteBuf.writeBoolean(false)
|
||||
byteBuf.writeLong(salt!!)
|
||||
Types.BYTE_ARRAY_PRIMITIVE.write(byteBuf, signature)
|
||||
}
|
||||
}
|
||||
|
||||
protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_8) || protocolVersion.equalTo(sharewareVersion) -> {
|
||||
Types.BYTE_ARRAY_PRIMITIVE.write(byteBuf, encryptedKey)
|
||||
Types.BYTE_ARRAY_PRIMITIVE.write(byteBuf, encryptedNonce)
|
||||
}
|
||||
|
||||
else -> {
|
||||
byteBuf.writeShort(encryptedKey.size)
|
||||
byteBuf.writeBytes(encryptedKey)
|
||||
byteBuf.writeShort(encryptedNonce!!.size)
|
||||
byteBuf.writeBytes(encryptedNonce)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,38 +2,65 @@ package com.viaversion.aas.codec.packet.login
|
|||
|
||||
import com.viaversion.aas.codec.packet.Packet
|
||||
import com.viaversion.aas.parseUndashedId
|
||||
import com.viaversion.aas.protocol.sharewareVersion
|
||||
import com.viaversion.aas.util.SignableProperty
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion
|
||||
import com.viaversion.viaversion.api.type.Type
|
||||
import com.viaversion.viaversion.api.type.Types
|
||||
import io.netty.buffer.ByteBuf
|
||||
import java.util.*
|
||||
|
||||
class LoginSuccess : Packet {
|
||||
lateinit var id: UUID
|
||||
lateinit var username: String
|
||||
private val properties = mutableListOf<SignableProperty>()
|
||||
private var strictErrorHandling: Boolean = false
|
||||
|
||||
override fun decode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
override fun decode(byteBuf: ByteBuf, protocolVersion: ProtocolVersion) {
|
||||
id = when {
|
||||
protocolVersion >= ProtocolVersion.v1_16.version -> {
|
||||
Type.UUID_INT_ARRAY.read(byteBuf)
|
||||
protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_16) -> {
|
||||
Types.UUID.read(byteBuf)
|
||||
}
|
||||
protocolVersion >= ProtocolVersion.v1_7_6.version -> {
|
||||
UUID.fromString(Type.STRING.read(byteBuf))
|
||||
protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_7_6) || protocolVersion.equalTo(sharewareVersion) -> {
|
||||
UUID.fromString(Types.STRING.read(byteBuf))
|
||||
}
|
||||
else -> parseUndashedId(Type.STRING.read(byteBuf))
|
||||
else -> parseUndashedId(Types.STRING.read(byteBuf))
|
||||
}
|
||||
username = Types.STRING.read(byteBuf)
|
||||
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_19)) {
|
||||
val properties = Types.VAR_INT.readPrimitive(byteBuf)
|
||||
for (i in 0 until properties) {
|
||||
val name = Types.STRING.read(byteBuf)
|
||||
val value = Types.STRING.read(byteBuf)
|
||||
val signature = Types.OPTIONAL_STRING.read(byteBuf)
|
||||
this.properties.add(SignableProperty(name, value, signature))
|
||||
}
|
||||
}
|
||||
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_20_5)) {
|
||||
strictErrorHandling = byteBuf.readBoolean()
|
||||
}
|
||||
username = Type.STRING.read(byteBuf)
|
||||
}
|
||||
|
||||
override fun encode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
override fun encode(byteBuf: ByteBuf, protocolVersion: ProtocolVersion) {
|
||||
when {
|
||||
protocolVersion >= ProtocolVersion.v1_16.version -> {
|
||||
Type.UUID_INT_ARRAY.write(byteBuf, id)
|
||||
protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_16) -> {
|
||||
Types.UUID.write(byteBuf, id)
|
||||
}
|
||||
protocolVersion >= ProtocolVersion.v1_7_6.version -> {
|
||||
Type.STRING.write(byteBuf, id.toString())
|
||||
protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_7_6) || protocolVersion.equalTo(sharewareVersion) -> {
|
||||
Types.STRING.write(byteBuf, id.toString())
|
||||
}
|
||||
else -> Type.STRING.write(byteBuf, id.toString().replace("-", ""))
|
||||
else -> Types.STRING.write(byteBuf, id.toString().replace("-", ""))
|
||||
}
|
||||
Types.STRING.write(byteBuf, username)
|
||||
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_19)) {
|
||||
Types.VAR_INT.writePrimitive(byteBuf, properties.size)
|
||||
for (property in properties) {
|
||||
Types.STRING.write(byteBuf, property.key)
|
||||
Types.STRING.write(byteBuf, property.value)
|
||||
Types.OPTIONAL_STRING.write(byteBuf, property.signature)
|
||||
}
|
||||
}
|
||||
if (protocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_20_5)) {
|
||||
byteBuf.writeBoolean(strictErrorHandling)
|
||||
}
|
||||
Type.STRING.write(byteBuf, username)
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package com.viaversion.aas.codec.packet.login
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet
|
||||
import com.viaversion.aas.readRemainingBytes
|
||||
import com.viaversion.viaversion.api.type.Type
|
||||
import io.netty.buffer.ByteBuf
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
class PluginRequest : Packet {
|
||||
var id by Delegates.notNull<Int>()
|
||||
lateinit var channel: String
|
||||
lateinit var data: ByteArray
|
||||
override fun decode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
id = Type.VAR_INT.readPrimitive(byteBuf)
|
||||
channel = Type.STRING.read(byteBuf)
|
||||
data = readRemainingBytes(byteBuf)
|
||||
}
|
||||
|
||||
override fun encode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
Type.VAR_INT.writePrimitive(byteBuf, id)
|
||||
Type.STRING.write(byteBuf, channel)
|
||||
byteBuf.writeBytes(data)
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package com.viaversion.aas.codec.packet.login
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet
|
||||
import com.viaversion.aas.readRemainingBytes
|
||||
import com.viaversion.viaversion.api.type.Type
|
||||
import io.netty.buffer.ByteBuf
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
class PluginResponse : Packet {
|
||||
var id by Delegates.notNull<Int>()
|
||||
var success by Delegates.notNull<Boolean>()
|
||||
lateinit var data: ByteArray
|
||||
override fun decode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
id = Type.VAR_INT.readPrimitive(byteBuf)
|
||||
success = byteBuf.readBoolean()
|
||||
if (success) {
|
||||
data = readRemainingBytes(byteBuf)
|
||||
}
|
||||
}
|
||||
|
||||
override fun encode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
Type.VAR_INT.writePrimitive(byteBuf, id)
|
||||
byteBuf.writeBoolean(success)
|
||||
if (success) {
|
||||
byteBuf.writeBytes(data)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
package com.viaversion.aas.codec.packet.play
|
||||
|
||||
import com.viaversion.aas.codec.packet.Packet
|
||||
import com.viaversion.aas.readByteArray
|
||||
import com.viaversion.aas.readRemainingBytes
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion
|
||||
import com.viaversion.viaversion.api.type.Type
|
||||
import io.netty.buffer.ByteBuf
|
||||
|
||||
class PluginMessage : Packet {
|
||||
lateinit var channel: String
|
||||
lateinit var data: ByteArray
|
||||
|
||||
override fun decode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
channel = Type.STRING.read(byteBuf)
|
||||
data = if (protocolVersion <= ProtocolVersion.v1_7_6.version) {
|
||||
byteBuf.readByteArray(readExtendedForgeShort(byteBuf))
|
||||
} else {
|
||||
readRemainingBytes(byteBuf)
|
||||
}
|
||||
}
|
||||
|
||||
override fun encode(byteBuf: ByteBuf, protocolVersion: Int) {
|
||||
Type.STRING.write(byteBuf, channel)
|
||||
if (protocolVersion <= ProtocolVersion.v1_7_6.version) {
|
||||
writeExtendedForgeShort(byteBuf, data.size)
|
||||
}
|
||||
byteBuf.writeBytes(data)
|
||||
}
|
||||
|
||||
// stolen from https://github.com/VelocityPowered/Velocity/blob/27ccb9d387fc9a0aecd5c4b570d7d957558efddc/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java#L418
|
||||
fun readExtendedForgeShort(buf: ByteBuf): Int {
|
||||
var low = buf.readUnsignedShort()
|
||||
var high = 0
|
||||
if (low and 0x8000 != 0) {
|
||||
low = low and 0x7FFF
|
||||
high = buf.readUnsignedByte().toInt()
|
||||
}
|
||||
return high and 0xFF shl 15 or low
|
||||
}
|
||||
|
||||
fun writeExtendedForgeShort(buf: ByteBuf, toWrite: Int) {
|
||||
var low = toWrite and 0x7FFF
|
||||
val high = toWrite.and(0x7F8000).shr(15)
|
||||
if (high != 0) {
|
||||
low = low or 0x8000
|
||||
}
|
||||
buf.writeShort(low)
|
||||
if (high != 0) {
|
||||
buf.writeByte(high)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,13 +3,13 @@ package com.viaversion.aas.command
|
|||
import com.viaversion.viaversion.api.command.ViaCommandSender
|
||||
|
||||
object ReloadCommand : Command {
|
||||
override val info = "Alias for 'viaversion aasreload'"
|
||||
override val info = "Alias for 'viaversion reload'"
|
||||
|
||||
override fun suggest(sender: ViaCommandSender, alias: String, args: List<String>): List<String> {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override fun execute(sender: ViaCommandSender, alias: String, args: List<String>) {
|
||||
ViaAspirinCommand.execute(sender, alias, listOf("aasreload"))
|
||||
ViaAspirinCommand.execute(sender, alias, listOf("reload"))
|
||||
}
|
||||
}
|
|
@ -77,6 +77,6 @@ object VIAaaSConsole : SimpleTerminalConsole(), ViaCommandSender {
|
|||
}
|
||||
|
||||
override fun hasPermission(p0: String): Boolean = true
|
||||
override fun getUUID(): UUID = UUID.fromString(name)
|
||||
override fun getUUID(): UUID = UUID.nameUUIDFromBytes(name.toByteArray())
|
||||
override fun getName(): String = "VIAaaS Console"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.viaversion.aas.command
|
||||
|
||||
import com.viaversion.aas.command.sub.AspirinReloadSubCommand
|
||||
import com.viaversion.aas.command.sub.ConnectionsSubCommand
|
||||
import com.viaversion.aas.command.sub.StopSubCommand
|
||||
import com.viaversion.aas.command.sub.VIAaaSSubCommand
|
||||
|
@ -14,7 +13,6 @@ object ViaAspirinCommand : ViaCommandHandler(), Command {
|
|||
registerSubCommand(StopSubCommand)
|
||||
registerSubCommand(VIAaaSSubCommand)
|
||||
registerSubCommand(ConnectionsSubCommand)
|
||||
registerSubCommand(AspirinReloadSubCommand)
|
||||
}
|
||||
|
||||
override fun suggest(sender: ViaCommandSender, alias: String, args: List<String>): List<String> {
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
package com.viaversion.aas.command.sub
|
||||
|
||||
import com.viaversion.aas.config.VIAaaSConfig
|
||||
import com.viaversion.viaversion.api.command.ViaCommandSender
|
||||
import com.viaversion.viaversion.api.command.ViaSubCommand
|
||||
|
||||
object AspirinReloadSubCommand : ViaSubCommand() {
|
||||
override fun name() = "aasreload"
|
||||
override fun description() = "Reloads VIAaaS config"
|
||||
|
||||
override fun execute(sender: ViaCommandSender, args: Array<String>): Boolean {
|
||||
VIAaaSConfig.reloadConfig()
|
||||
sender.sendMessage("Reloaded VIAaaS config. Some configurations may need a restart.")
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -1,12 +1,11 @@
|
|||
package com.viaversion.aas.command.sub
|
||||
|
||||
import com.viaversion.aas.handler.MinecraftHandler
|
||||
import com.viaversion.aas.parseProtocol
|
||||
import com.viaversion.viaversion.api.Via
|
||||
import com.viaversion.viaversion.api.command.ViaCommandSender
|
||||
import com.viaversion.viaversion.api.command.ViaSubCommand
|
||||
|
||||
object ConnectionsSubCommand : ViaSubCommand() {
|
||||
object ConnectionsSubCommand : ViaSubCommand {
|
||||
override fun name(): String = "connections"
|
||||
override fun description(): String = "Lists VIAaaS connections"
|
||||
override fun execute(p0: ViaCommandSender, p1: Array<out String>): Boolean {
|
||||
|
@ -14,9 +13,9 @@ object ConnectionsSubCommand : ViaSubCommand() {
|
|||
Via.getManager().connectionManager.connections.forEach {
|
||||
val handler = it.channel?.pipeline()?.get(MinecraftHandler::class.java)
|
||||
val backAddr = handler?.endRemoteAddress
|
||||
val pVer = it.protocolInfo?.protocolVersion?.parseProtocol()
|
||||
val pVer = it.protocolInfo?.protocolVersion()
|
||||
val backName = it.protocolInfo?.username
|
||||
val backVer = it.protocolInfo?.serverProtocolVersion?.parseProtocol()
|
||||
val backVer = it.protocolInfo?.serverProtocolVersion()
|
||||
val pAddr = handler?.data?.frontHandler?.endRemoteAddress
|
||||
p0.sendMessage("$pAddr $pVer -> $backVer ($backName) $backAddr")
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import com.viaversion.aas.AspirinServer
|
|||
import com.viaversion.viaversion.api.command.ViaCommandSender
|
||||
import com.viaversion.viaversion.api.command.ViaSubCommand
|
||||
|
||||
object StopSubCommand : ViaSubCommand() {
|
||||
object StopSubCommand : ViaSubCommand {
|
||||
override fun name() = "stop"
|
||||
override fun description(): String = "Stops VIAaaS"
|
||||
override fun execute(sender: ViaCommandSender, p1: Array<String>): Boolean {
|
||||
|
|
|
@ -4,15 +4,15 @@ import com.viaversion.aas.AspirinServer
|
|||
import com.viaversion.viaversion.api.command.ViaCommandSender
|
||||
import com.viaversion.viaversion.api.command.ViaSubCommand
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
object VIAaaSSubCommand : ViaSubCommand() {
|
||||
object VIAaaSSubCommand : ViaSubCommand {
|
||||
override fun name(): String = "viaaas"
|
||||
override fun description(): String = "Info about VIAaaS"
|
||||
override fun execute(p0: ViaCommandSender, p1: Array<out String>): Boolean {
|
||||
p0.sendMessage("VIAaaS version ${AspirinServer.version}")
|
||||
CoroutineScope(Dispatchers.IO).launch { p0.sendMessage(AspirinServer.updaterCheckMessage()) }
|
||||
CoroutineScope(Job()).launch { p0.sendMessage(AspirinServer.updaterCheckMessage()) }
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
package com.viaversion.aas.config
|
||||
|
||||
import com.google.common.net.HostAndPort
|
||||
import com.viaversion.aas.secureRandom
|
||||
import com.viaversion.aas.util.AddressParser
|
||||
import com.viaversion.aas.viaaasLoggerJava
|
||||
import com.viaversion.viaversion.util.Config
|
||||
import net.coobird.thumbnailator.Thumbnails
|
||||
import net.coobird.thumbnailator.filters.Canvas
|
||||
|
@ -11,42 +14,103 @@ import java.net.URI
|
|||
import java.net.URL
|
||||
import java.util.*
|
||||
|
||||
object VIAaaSConfig : Config(File("config/viaaas.yml")) {
|
||||
object VIAaaSConfig : Config(File("config/viaaas.yml"), viaaasLoggerJava), com.viaversion.viaversion.api.configuration.Config {
|
||||
var defaultParameters: Map<Int, AddressParser> = emptyMap()
|
||||
var bindAddresses = emptyList<HostAndPort>()
|
||||
var hostName: List<String> = emptyList()
|
||||
var blockLocalAddress = true
|
||||
var requireHostName: Boolean = true
|
||||
var defaultBackendPort: Int? = null
|
||||
var blockedBackAddresses: List<String> = emptyList()
|
||||
var allowedBackAddresses: List<String> = emptyList()
|
||||
var forceOnlineMode: Boolean = false
|
||||
var showVersionPing: Boolean = true
|
||||
var showBrandInfo: Boolean = true
|
||||
var rateLimitWs: Double = 1.0
|
||||
var rateLimitConnectionMc: Double = 10.0
|
||||
var listeningWsLimit: Int = 16
|
||||
var jwtSecret: String = ""
|
||||
var rateLimitLoginMc: Double = 0.2
|
||||
var faviconUrl: String? = null
|
||||
var maxPlayers: Int? = null
|
||||
var backendProxy: URI? = null
|
||||
var protocolDetectorCache: Int = 30
|
||||
var compressionLevel: Int = 6
|
||||
|
||||
init {
|
||||
reloadConfig()
|
||||
reload()
|
||||
}
|
||||
|
||||
override fun reloadConfig() {
|
||||
super.reloadConfig()
|
||||
override fun reload() {
|
||||
super.reload()
|
||||
reloadFields()
|
||||
}
|
||||
|
||||
private fun reloadFields() {
|
||||
reloadIcon()
|
||||
defaultParameters = this.get("default-parameters", emptyMap<Int, String>())!!.map {
|
||||
(it.key as Number).toInt() to AddressParser().parse(it.value)
|
||||
}.toMap()
|
||||
bindAddresses = this.getStringList("bind-addresses").map { HostAndPort.fromString(it).withDefaultPort(25565) }
|
||||
hostName = this.get("host-name", emptyList<String>())!!.map { it }
|
||||
blockLocalAddress = this.getBoolean("block-local-address", true)
|
||||
requireHostName = this.getBoolean("require-host-name", true)
|
||||
defaultBackendPort = this.getInt("default-backend-port", 25565).let { if (it == -1) null else it }
|
||||
blockedBackAddresses = this.get("blocked-back-addresses", emptyList())!!
|
||||
allowedBackAddresses = this.get("allowed-back-addresses", emptyList())!!
|
||||
forceOnlineMode = this.getBoolean("force-online-mode", false)
|
||||
showVersionPing = this.getBoolean("show-version-ping", true)
|
||||
showBrandInfo = this.getBoolean("show-brand-info", true)
|
||||
rateLimitWs = this.getDouble("rate-limit-ws", 1.0)
|
||||
rateLimitConnectionMc = this.getDouble("rate-limit-connection-mc", 10.0)
|
||||
listeningWsLimit = this.getInt("listening-ws-limit", 16)
|
||||
jwtSecret = this.getString("jwt-secret", null).let {
|
||||
if (it.isNullOrBlank()) throw IllegalStateException("invalid jwt-secret") else it
|
||||
}
|
||||
rateLimitLoginMc = this.getDouble("rate-limit-login-mc", 0.2)
|
||||
maxPlayers = this.getInt("max-players", 20).let { if (it == -1) null else it }
|
||||
backendProxy = this.getString("backend-proxy", "").let { if (it.isNullOrEmpty()) null else URI.create(it) }
|
||||
protocolDetectorCache = this.getInt("protocol-detector-cache", 30)
|
||||
compressionLevel = this.getInt("compression-level", 6)
|
||||
}
|
||||
|
||||
fun reloadIcon() {
|
||||
private fun reloadIcon() {
|
||||
val rawUrl = this.getString("favicon-url", "")!!
|
||||
faviconUrl = when {
|
||||
rawUrl.isEmpty() -> null
|
||||
rawUrl.startsWith("data:image/png;base64,") -> rawUrl.filter { !it.isWhitespace() }
|
||||
else -> "data:image/png;base64," + Base64.getEncoder().encodeToString(
|
||||
ByteArrayOutputStream().also {
|
||||
Thumbnails.of(URL(rawUrl))
|
||||
.size(64, 64)
|
||||
.addFilter(Canvas(64, 64, Positions.CENTER, false))
|
||||
.outputFormat("png").toOutputStream(it)
|
||||
}.toByteArray()
|
||||
)
|
||||
try {
|
||||
faviconUrl = when {
|
||||
rawUrl.isEmpty() -> null
|
||||
rawUrl.startsWith("data:image/png;base64,") -> rawUrl.filter { !it.isWhitespace() }
|
||||
else -> "data:image/png;base64," + Base64.getEncoder().encodeToString(
|
||||
ByteArrayOutputStream().also {
|
||||
Thumbnails.of(URL(rawUrl))
|
||||
.size(64, 64)
|
||||
.addFilter(Canvas(64, 64, Positions.CENTER, false))
|
||||
.outputFormat("png")
|
||||
.toOutputStream(it)
|
||||
}.toByteArray()
|
||||
)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getUnsupportedOptions() = emptyList<String>()
|
||||
override fun getDefaultConfigURL() = VIAaaSConfig::class.java.classLoader.getResource("viaaas.yml")!!
|
||||
override fun handleConfig(map: MutableMap<String, Any>) {
|
||||
// Migration from older config versions
|
||||
fixConfig(map)
|
||||
upgradeConfig(map)
|
||||
}
|
||||
|
||||
private fun fixConfig(map: MutableMap<String, Any>) {
|
||||
if (map["jwt-secret"]?.toString().isNullOrBlank()) {
|
||||
map["jwt-secret"] = Base64.getEncoder()
|
||||
.encodeToString(ByteArray(64)
|
||||
.also { secureRandom.nextBytes(it) })
|
||||
}
|
||||
}
|
||||
|
||||
private fun upgradeConfig(map: MutableMap<String, Any>) {
|
||||
if (map["host-name"] is String) {
|
||||
map["host-name"] = map["host-name"].toString().split(',').map { it.trim() }
|
||||
}
|
||||
|
@ -54,45 +118,13 @@ object VIAaaSConfig : Config(File("config/viaaas.yml")) {
|
|||
val oldSocks = map.remove("backend-socks5-proxy-address")
|
||||
val oldSocksPort = map.remove("backend-socks5-proxy-port")
|
||||
if (oldSocks is String && oldSocks.isNotBlank()) {
|
||||
map["backend-proxy"] = "socks5://$oldSocks:$oldSocksPort"
|
||||
map["backend-proxy"] = "socks5://${HostAndPort.fromParts(oldSocks, oldSocksPort.toString().toInt())}"
|
||||
}
|
||||
|
||||
val oldBind = map.remove("bind-address")?.toString()
|
||||
val oldPort = map.remove("port")?.toString()
|
||||
if (!oldBind.isNullOrEmpty() && !oldPort.isNullOrEmpty()) {
|
||||
map["bind-addresses"] = listOf(HostAndPort.fromParts(oldBind, oldPort.toInt()).toString())
|
||||
}
|
||||
}
|
||||
|
||||
val port: Int get() = this.getInt("port", 25565)
|
||||
val bindAddress: String get() = this.getString("bind-address", "localhost")!!
|
||||
val hostName: List<String>
|
||||
get() = this.get("host-name", List::class.java, listOf("viaaas.localhost"))!!.map { it.toString() }
|
||||
val mcRsaSize: Int get() = this.getInt("mc-rsa-size", 4096)
|
||||
val blockLocalAddress: Boolean get() = this.getBoolean("block-local-address", true)
|
||||
val requireHostName: Boolean get() = this.getBoolean("require-host-name", true)
|
||||
val defaultBackendPort: Int? get() = this.getInt("default-backend-port", 25565).let { if (it == -1) null else it }
|
||||
val blockedBackAddresses: List<String>
|
||||
get() = this.get(
|
||||
"blocked-back-addresses",
|
||||
List::class.java,
|
||||
emptyList<String>()
|
||||
)!!.map { it.toString() }
|
||||
val allowedBackAddresses: List<String>
|
||||
get() = this.get(
|
||||
"allowed-back-addresses",
|
||||
List::class.java,
|
||||
emptyList<String>()
|
||||
)!!.map { it.toString() }
|
||||
val forceOnlineMode: Boolean get() = this.getBoolean("force-online-mode", false)
|
||||
val showVersionPing: Boolean get() = this.getBoolean("show-version-ping", true)
|
||||
val showBrandInfo: Boolean get() = this.getBoolean("show-brand-info", true)
|
||||
val rateLimitWs: Double get() = this.getDouble("rate-limit-ws", 1.0)
|
||||
val rateLimitConnectionMc: Double get() = this.getDouble("rate-limit-connection-mc", 10.0)
|
||||
val listeningWsLimit: Int get() = this.getInt("listening-ws-limit", 16)
|
||||
val jwtSecret: String
|
||||
get() = this.getString("jwt-secret", null).let {
|
||||
if (it.isNullOrBlank()) throw IllegalStateException("invalid jwt-secret") else it
|
||||
}
|
||||
val rateLimitLoginMc: Double get() = this.getDouble("rate-limit-login-mc", 0.2)
|
||||
var faviconUrl: String? = null
|
||||
val maxPlayers: Int? get() = this.getInt("max-players", 20).let { if (it == -1) null else it }
|
||||
val backendProxy: URI?
|
||||
get() = this.getString("backend-proxy", "").let { if (it.isNullOrEmpty()) null else URI.create(it) }
|
||||
val protocolDetectorCache: Int
|
||||
get() = this.getInt("protocol-detector-cache", 30)
|
||||
}
|
||||
|
|
|
@ -7,16 +7,28 @@ import com.viaversion.viaversion.protocol.ProtocolPipelineImpl
|
|||
import io.netty.channel.Channel
|
||||
import io.netty.channel.ChannelInitializer
|
||||
import io.netty.handler.timeout.ReadTimeoutHandler
|
||||
import net.raphimc.vialegacy.api.LegacyProtocolVersion
|
||||
import net.raphimc.vialegacy.api.protocol.PreNettyBaseProtocol
|
||||
import net.raphimc.vialegacy.netty.PreNettyLengthCodec
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.URI
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class BackEndInit(val connectionData: ConnectionData, val proxyUri: URI?, val proxyAddress: InetSocketAddress?) :
|
||||
class BackEndInit(private val connectionData: ConnectionData, private val proxyUri: URI?, private val proxyAddress: InetSocketAddress?) :
|
||||
ChannelInitializer<Channel>() {
|
||||
override fun initChannel(ch: Channel) {
|
||||
val user = UserConnectionImpl(ch, true)
|
||||
ProtocolPipelineImpl(user)
|
||||
ch.pipeline().also { addProxyHandler(it, proxyUri, proxyAddress) }
|
||||
val pipeline = ProtocolPipelineImpl(user)
|
||||
val version = connectionData.backServerVer!!
|
||||
val isLegacy = version.olderThanOrEqualTo(LegacyProtocolVersion.r1_6_4)
|
||||
|
||||
if (isLegacy) {
|
||||
pipeline.add(PreNettyBaseProtocol.INSTANCE)
|
||||
}
|
||||
|
||||
ch.pipeline()
|
||||
.also { addProxyHandler(it, proxyUri, proxyAddress) }
|
||||
.also { if (isLegacy) it.addLast("vl-prenetty", PreNettyLengthCodec(user)) }
|
||||
// "crypto"
|
||||
.addLast("frame", FrameCodec())
|
||||
// compress
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
package com.viaversion.aas.handler
|
||||
|
||||
import com.viaversion.aas.codec.CompressionCodec
|
||||
import com.viaversion.aas.codec.CryptoCodec
|
||||
import com.viaversion.aas.handler.state.ConnectionState
|
||||
import com.viaversion.aas.handler.state.HandshakeState
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion
|
||||
import io.netty.channel.Channel
|
||||
|
||||
class ConnectionData(
|
||||
val frontChannel: Channel,
|
||||
var backChannel: Channel? = null,
|
||||
var state: ConnectionState = HandshakeState(),
|
||||
var frontVer: Int? = null,
|
||||
var backServerVer: Int? = null,
|
||||
var frontVer: ProtocolVersion? = null,
|
||||
var backServerVer: ProtocolVersion? = null,
|
||||
var autoDetectProtocol: Boolean = false
|
||||
) {
|
||||
val frontHandler get() = frontChannel.pipeline()[MinecraftHandler::class.java]
|
||||
val backHandler get() = backChannel?.pipeline()?.get(MinecraftHandler::class.java)
|
||||
val frontEncrypted get() = frontChannel.pipeline()[CryptoCodec::class.java] != null
|
||||
val compressionLevel get() = frontChannel.pipeline()[CompressionCodec::class.java]?.threshold ?: -1
|
||||
}
|
|
@ -6,6 +6,7 @@ import com.viaversion.aas.readRemainingBytes
|
|||
import com.viaversion.aas.send
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion
|
||||
import com.viaversion.viaversion.api.type.Type
|
||||
import com.viaversion.viaversion.api.type.Types
|
||||
import io.netty.buffer.ByteBufAllocator
|
||||
import io.netty.buffer.Unpooled
|
||||
import io.netty.channel.Channel
|
||||
|
@ -20,7 +21,7 @@ fun forward(handler: MinecraftHandler, packet: Packet, flush: Boolean = false) {
|
|||
send(handler.other!!, packet, flush)
|
||||
}
|
||||
|
||||
fun is17(handler: MinecraftHandler) = handler.data.frontVer!! <= ProtocolVersion.v1_7_6.version
|
||||
fun is17(handler: MinecraftHandler) = handler.data.frontVer!!.olderThanOrEqualTo(ProtocolVersion.v1_7_6)
|
||||
|
||||
fun addProxyHandler(pipe: ChannelPipeline, proxyUri: URI?, socket: InetSocketAddress?) {
|
||||
if (proxyUri != null) {
|
||||
|
@ -37,10 +38,14 @@ fun addProxyHandler(pipe: ChannelPipeline, proxyUri: URI?, socket: InetSocketAdd
|
|||
}
|
||||
|
||||
fun decodeBrand(data: ByteArray, is17: Boolean): String {
|
||||
return if (is17) {
|
||||
String(data, Charsets.UTF_8)
|
||||
} else {
|
||||
Type.STRING.read(Unpooled.wrappedBuffer(data))
|
||||
return when {
|
||||
data.isEmpty() -> ""
|
||||
is17 -> {
|
||||
String(data, Charsets.UTF_8)
|
||||
}
|
||||
else -> {
|
||||
Types.STRING.read(Unpooled.wrappedBuffer(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,7 +55,7 @@ fun encodeBrand(string: String, is17: Boolean): ByteArray {
|
|||
} else {
|
||||
val buf = ByteBufAllocator.DEFAULT.buffer()
|
||||
try {
|
||||
Type.STRING.write(buf, string)
|
||||
Types.STRING.write(buf, string)
|
||||
readRemainingBytes(buf)
|
||||
} finally {
|
||||
buf.release()
|
||||
|
@ -62,7 +67,7 @@ fun encodeBrand(string: String, is17: Boolean): ByteArray {
|
|||
fun setCompression(channel: Channel, threshold: Int) {
|
||||
val pipe = channel.pipeline()
|
||||
|
||||
if (threshold == -1) {
|
||||
if (threshold <= 0) {
|
||||
if (pipe["compress"] != null) pipe.remove("compress")
|
||||
} else {
|
||||
if (pipe["compress"] != null) {
|
|
@ -10,10 +10,11 @@ import io.netty.channel.SimpleChannelInboundHandler
|
|||
import io.netty.handler.proxy.ProxyConnectException
|
||||
import io.netty.handler.proxy.ProxyHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.cancel
|
||||
import java.net.SocketAddress
|
||||
import java.nio.channels.ClosedChannelException
|
||||
import java.util.concurrent.ThreadLocalRandom
|
||||
|
||||
class MinecraftHandler(
|
||||
val data: ConnectionData,
|
||||
|
@ -21,8 +22,9 @@ class MinecraftHandler(
|
|||
) : SimpleChannelInboundHandler<Packet>() {
|
||||
lateinit var endRemoteAddress: SocketAddress
|
||||
val other: Channel? get() = if (frontEnd) data.backChannel else data.frontChannel
|
||||
val backEnd: Boolean get() = !frontEnd
|
||||
var loggedDc = false
|
||||
val coroutineScope = CoroutineScope(Dispatchers.Default)
|
||||
val coroutineScope = CoroutineScope(SupervisorJob())
|
||||
|
||||
override fun channelRead0(ctx: ChannelHandlerContext, packet: Packet) {
|
||||
if (!ctx.channel().isActive) return
|
||||
|
@ -61,8 +63,9 @@ class MinecraftHandler(
|
|||
if (cause is ProxyConnectException && failedProxy(ctx)) return
|
||||
if (cause is CancelCodecException) return
|
||||
if (cause is ClosedChannelException) return
|
||||
mcLogger.debug("Exception: ", cause)
|
||||
disconnect("$cause")
|
||||
val exceptionId = ThreadLocalRandom.current().nextInt().toUInt().toString(36)
|
||||
mcLogger.debug("Exception {}: ", exceptionId, cause)
|
||||
disconnect("$cause #$exceptionId")
|
||||
}
|
||||
|
||||
fun disconnect(s: String) {
|
||||
|
|
|
@ -1,29 +1,26 @@
|
|||
package com.viaversion.aas.handler.autoprotocol
|
||||
|
||||
import com.google.gson.JsonParser
|
||||
import com.viaversion.aas.codec.packet.Packet
|
||||
import com.viaversion.aas.codec.packet.status.StatusResponse
|
||||
import com.viaversion.aas.handler.MinecraftHandler
|
||||
import com.viaversion.aas.handler.state.ConnectionState
|
||||
import com.viaversion.aas.mcLogger
|
||||
import com.viaversion.aas.parseProtocol
|
||||
import com.viaversion.aas.util.StacklessException
|
||||
import com.viaversion.viaversion.api.protocol.packet.State
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion
|
||||
import io.netty.channel.ChannelHandlerContext
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class ProtocolDetectionState(val future: CompletableFuture<ProtocolVersion>) : ConnectionState {
|
||||
class ProtocolDetectionState(private val future: CompletableFuture<ProtocolVersion>) : ConnectionState {
|
||||
override val state: State
|
||||
get() = State.STATUS
|
||||
|
||||
override fun handlePacket(handler: MinecraftHandler, ctx: ChannelHandlerContext, packet: Packet) {
|
||||
handler.data.frontChannel.close()
|
||||
if (packet !is StatusResponse) throw StacklessException("Unexpected packet")
|
||||
val ver = JsonParser.parseString(packet.msg).asJsonObject
|
||||
.getAsJsonObject("version")["protocol"].asInt.parseProtocol()
|
||||
val ver = ProtocolVersion.getProtocol(packet.msg.asJsonObject.getAsJsonObject("version")["protocol"].asInt)
|
||||
future.complete(ver)
|
||||
mcLogger.info("A.D.: ${handler.endRemoteAddress} $ver")
|
||||
mcLogger.info("A.D.: {} {}", handler.endRemoteAddress, ver)
|
||||
}
|
||||
|
||||
override fun disconnect(handler: MinecraftHandler, msg: String) {
|
||||
|
|
|
@ -13,7 +13,7 @@ import com.viaversion.aas.handler.ConnectionData
|
|||
import com.viaversion.aas.handler.MinecraftHandler
|
||||
import com.viaversion.aas.handler.addProxyHandler
|
||||
import com.viaversion.aas.send
|
||||
import com.viaversion.viaversion.api.protocol.packet.State
|
||||
import com.viaversion.aas.util.IntendedState
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion
|
||||
import io.ktor.server.netty.*
|
||||
import io.netty.bootstrap.Bootstrap
|
||||
|
@ -24,16 +24,17 @@ import io.netty.channel.ChannelOption
|
|||
import io.netty.handler.timeout.ReadTimeoutHandler
|
||||
import io.netty.resolver.NoopAddressResolverGroup
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import java.net.InetSocketAddress
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
object ProtocolDetector {
|
||||
private val loader = CacheLoader.from<InetSocketAddress, CompletableFuture<ProtocolVersion>> { address ->
|
||||
val coroutineScope = CoroutineScope(SupervisorJob())
|
||||
val loader = CacheLoader.from<InetSocketAddress, CompletableFuture<ProtocolVersion>> { address ->
|
||||
val future = CompletableFuture<ProtocolVersion>()
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
coroutineScope.launch {
|
||||
try {
|
||||
val proxyUri = VIAaaSConfig.backendProxy
|
||||
val proxySocket = if (proxyUri == null) null else {
|
||||
|
@ -44,10 +45,11 @@ object ProtocolDetector {
|
|||
.resolver(NoopAddressResolverGroup.INSTANCE)
|
||||
.channelFactory(channelSocketFactory(AspirinServer.childLoop))
|
||||
.option(ChannelOption.TCP_NODELAY, true)
|
||||
.option(ChannelOption.TCP_FASTOPEN_CONNECT, true)
|
||||
.option(ChannelOption.IP_TOS, 0x18)
|
||||
.handler(object : ChannelInitializer<Channel>() {
|
||||
override fun initChannel(channel: Channel) {
|
||||
val data = ConnectionData(channel, state = ProtocolDetectionState(future), frontVer = -1)
|
||||
val data = ConnectionData(channel, state = ProtocolDetectionState(future), frontVer = ProtocolVersion.unknown)
|
||||
channel.pipeline().also { addProxyHandler(it, proxyUri, proxySocket) }
|
||||
.addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS))
|
||||
.addLast("frame", FrameCodec())
|
||||
|
@ -64,7 +66,7 @@ object ProtocolDetector {
|
|||
handshake.address = address.hostString
|
||||
handshake.port = address.port
|
||||
handshake.protocolId = -1
|
||||
handshake.nextState = State.STATUS
|
||||
handshake.intendedState = IntendedState.STATUS
|
||||
send(ch.channel(), handshake)
|
||||
send(ch.channel(), StatusRequest(), flush = true)
|
||||
}
|
||||
|
@ -76,9 +78,17 @@ object ProtocolDetector {
|
|||
future
|
||||
}
|
||||
|
||||
private val SERVER_VER = CacheBuilder.newBuilder()
|
||||
private val versionCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(VIAaaSConfig.protocolDetectorCache.toLong(), TimeUnit.SECONDS)
|
||||
.build(loader)
|
||||
|
||||
fun detectVersion(address: InetSocketAddress): CompletableFuture<ProtocolVersion> = SERVER_VER[address]
|
||||
fun detectVersion(address: InetSocketAddress): CompletableFuture<ProtocolVersion> {
|
||||
val future = versionCache[address]
|
||||
future.whenComplete { _, throwable ->
|
||||
if (throwable != null) {
|
||||
versionCache.invalidate(address)
|
||||
}
|
||||
}
|
||||
return future
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,14 +13,15 @@ interface ConnectionState {
|
|||
packet: Packet
|
||||
)
|
||||
val logDcInfo: Boolean get() = false
|
||||
val kickedByServer: Boolean get() = false
|
||||
|
||||
private fun logDisconnect(handler: MinecraftHandler, msg: String) {
|
||||
val formatted = "- ${handler.endRemoteAddress}: $msg"
|
||||
private fun logDisconnect(handler: MinecraftHandler, msg: String?) {
|
||||
val reason = msg ?: if (handler.backEnd && kickedByServer) "kicked" else "-"
|
||||
if (logDcInfo && !handler.loggedDc) {
|
||||
handler.loggedDc = true
|
||||
mcLogger.info(formatted)
|
||||
mcLogger.info("- {}: {}", handler.endRemoteAddress, reason)
|
||||
} else {
|
||||
mcLogger.debug(formatted)
|
||||
mcLogger.debug("- {}: {}", handler.endRemoteAddress, reason)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +30,10 @@ interface ConnectionState {
|
|||
}
|
||||
|
||||
fun onInactivated(handler: MinecraftHandler) {
|
||||
logDisconnect(handler, "-")
|
||||
logDisconnect(handler, null)
|
||||
handler.other?.close()
|
||||
}
|
||||
|
||||
fun start(handler: MinecraftHandler) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,11 +8,14 @@ import com.viaversion.aas.handler.BackEndInit
|
|||
import com.viaversion.aas.handler.MinecraftHandler
|
||||
import com.viaversion.aas.handler.autoprotocol.ProtocolDetector
|
||||
import com.viaversion.aas.handler.forward
|
||||
import com.viaversion.aas.util.IntendedState
|
||||
import com.viaversion.aas.util.StacklessException
|
||||
import com.viaversion.viaversion.api.protocol.packet.State
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion
|
||||
import com.viaversion.viaversion.api.type.Type
|
||||
import com.viaversion.viaversion.api.type.Types
|
||||
import io.ktor.server.netty.*
|
||||
import io.netty.bootstrap.Bootstrap
|
||||
import io.netty.buffer.ByteBufAllocator
|
||||
import io.netty.channel.Channel
|
||||
import io.netty.channel.ChannelOption
|
||||
import io.netty.channel.socket.SocketChannel
|
||||
|
@ -23,15 +26,18 @@ import kotlinx.coroutines.withTimeout
|
|||
import java.net.Inet4Address
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.URI
|
||||
import kotlin.math.ceil
|
||||
|
||||
private suspend fun createBackChannel(
|
||||
handler: MinecraftHandler,
|
||||
socketAddr: InetSocketAddress,
|
||||
state: State,
|
||||
state: IntendedState,
|
||||
extraData: String?,
|
||||
proxyUri: URI?,
|
||||
proxyAddress: InetSocketAddress?
|
||||
): Channel {
|
||||
autoDetectVersion(handler, socketAddr)
|
||||
|
||||
val loop = handler.data.frontChannel.eventLoop()
|
||||
val channel = Bootstrap()
|
||||
.handler(BackEndInit(handler.data, proxyUri, proxyAddress))
|
||||
|
@ -40,6 +46,7 @@ private suspend fun createBackChannel(
|
|||
.option(ChannelOption.WRITE_BUFFER_WATER_MARK, AspirinServer.bufferWaterMark)
|
||||
.option(ChannelOption.IP_TOS, 0x18)
|
||||
.option(ChannelOption.TCP_NODELAY, true)
|
||||
.option(ChannelOption.TCP_FASTOPEN_CONNECT, true)
|
||||
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10_000) // We need to show the error before the client timeout
|
||||
.resolver(NoopAddressResolverGroup.INSTANCE)
|
||||
.connect(socketAddr)
|
||||
|
@ -47,14 +54,16 @@ private suspend fun createBackChannel(
|
|||
.channel()
|
||||
(channel.pipeline()["proxy"] as? ProxyHandler)?.connectFuture()?.suspendAwait()
|
||||
|
||||
mcLogger.info("+ ${state.name.substring(0, 1)} ${handler.endRemoteAddress} -> $socketAddr")
|
||||
if (state == IntendedState.LOGIN) {
|
||||
mcLogger.info("+ L {} -> {}", handler.endRemoteAddress, socketAddr)
|
||||
} else {
|
||||
mcLogger.debug("+ {} {} -> {}", state.name[0], handler.endRemoteAddress, socketAddr)
|
||||
}
|
||||
handler.data.backChannel = channel as SocketChannel
|
||||
|
||||
autoDetectVersion(handler, socketAddr)
|
||||
|
||||
val packet = Handshake()
|
||||
packet.nextState = state
|
||||
packet.protocolId = handler.data.frontVer!!
|
||||
packet.intendedState = state
|
||||
packet.protocolId = handler.data.frontVer!!.version
|
||||
packet.address = socketAddr.hostString + if (extraData != null) 0.toChar() + extraData else ""
|
||||
packet.port = socketAddr.port
|
||||
|
||||
|
@ -66,32 +75,28 @@ private suspend fun createBackChannel(
|
|||
}
|
||||
|
||||
private suspend fun autoDetectVersion(handler: MinecraftHandler, socketAddr: InetSocketAddress) {
|
||||
if (handler.data.backServerVer == -2) { // Auto
|
||||
if (handler.data.autoDetectProtocol) { // Auto
|
||||
var detectedProtocol: ProtocolVersion? = null
|
||||
try {
|
||||
detectedProtocol = withTimeout(10_000) {
|
||||
ProtocolDetector.detectVersion(socketAddr).await()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
mcLogger.warn("Failed to detect version of $socketAddr: $e")
|
||||
mcLogger.warn("Failed to detect version of {}: {}", socketAddr, e.toString())
|
||||
mcLogger.debug("Stacktrace: ", e)
|
||||
}
|
||||
|
||||
if (detectedProtocol != null
|
||||
handler.data.backServerVer = if (detectedProtocol != null
|
||||
&& detectedProtocol.version !in arrayOf(-1, -2)
|
||||
&& ProtocolVersion.isRegistered(detectedProtocol.version)
|
||||
) {
|
||||
handler.data.backServerVer = detectedProtocol.version
|
||||
} else {
|
||||
handler.data.backServerVer = 47 // fallback 1.8
|
||||
}
|
||||
) detectedProtocol else ProtocolVersion.v1_8 // fallback
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun tryBackAddresses(
|
||||
handler: MinecraftHandler,
|
||||
addresses: Iterable<InetSocketAddress>,
|
||||
state: State,
|
||||
state: IntendedState,
|
||||
extraData: String?
|
||||
) {
|
||||
var latestException: Exception? = null
|
||||
|
@ -128,6 +133,7 @@ private suspend fun resolveBackendAddresses(hostAndPort: HostAndPort): List<Inet
|
|||
return when {
|
||||
removedEndDot.endsWith(".onion", ignoreCase = true) ->
|
||||
listOf(InetSocketAddress.createUnresolved(removedEndDot, srvResolved.port))
|
||||
|
||||
else -> AspirinServer.dnsResolver
|
||||
.resolveAll(srvResolved.host)
|
||||
.suspendAwait()
|
||||
|
@ -139,14 +145,45 @@ private suspend fun resolveBackendAddresses(hostAndPort: HostAndPort): List<Inet
|
|||
|
||||
suspend fun connectBack(
|
||||
handler: MinecraftHandler,
|
||||
address: String,
|
||||
port: Int,
|
||||
state: State,
|
||||
address: HostAndPort,
|
||||
state: IntendedState,
|
||||
extraData: String? = null
|
||||
) {
|
||||
val addresses = resolveBackendAddresses(HostAndPort.fromParts(address, port))
|
||||
val addresses = resolveBackendAddresses(address)
|
||||
|
||||
if (addresses.isEmpty()) throw StacklessException("Hostname has no IP addresses")
|
||||
|
||||
tryBackAddresses(handler, addresses, state, extraData)
|
||||
}
|
||||
|
||||
val openAuthMagic = 0xfdebf3fd.toInt()
|
||||
|
||||
// https://github.com/RaphiMC/OpenAuthMod/blob/fa66e78fe5c0e748c1b8c61624bf283fb8bc06dd/src/main/java/com/github/oam/utils/IntTo3ByteCodec.java#L16
|
||||
fun encodeCompressionOpenAuth(channel: String, id: Int, data: ByteArray): IntArray {
|
||||
val buffer = ByteBufAllocator.DEFAULT.buffer()
|
||||
try {
|
||||
Types.STRING.write(buffer, channel)
|
||||
Types.VAR_INT.writePrimitive(buffer, id)
|
||||
buffer.writeBytes(data)
|
||||
val out = IntArray(2 + ceil(buffer.readableBytes() / 3.0).toInt())
|
||||
|
||||
out[0] = openAuthMagic
|
||||
out[out.size - 1] = openAuthMagic
|
||||
|
||||
for (i in 1 until out.size - 1) {
|
||||
var entry = 0xC0000000.toInt().or(buffer.readUnsignedByte().toInt().shl(16))
|
||||
if (buffer.isReadable) {
|
||||
entry = entry.or(0x20000000).or(buffer.readUnsignedByte().toInt().shl(8))
|
||||
}
|
||||
if (buffer.isReadable) {
|
||||
entry = entry.or(0x10000000).or(buffer.readUnsignedByte().toInt())
|
||||
}
|
||||
|
||||
out[i] = entry
|
||||
}
|
||||
|
||||
return out
|
||||
} finally {
|
||||
buffer.release()
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user