Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
dexuby committed Feb 22, 2024
0 parents commit c7f10f4
Show file tree
Hide file tree
Showing 19 changed files with 780 additions and 0 deletions.
19 changes: 19 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# IntelliJ
*.iml
*.ipr
*.iws
.idea/
.settings/

# Build
build/
bin/
dist/
manifest.mf

# Maven
target/
build.xml

# Other Stuff
logs/
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## Unfinished API for the League of Legends client endpoints of the locally running server

### How to obtain an API instance?
Make sure to start the League of Legends client before you call the #hookAPI method,
the system will fetch all tokens and ports from the running process so you don't have to
do or provide anything manually.
```java
final LeagueClientAPI api = LeagueClient.getInstance().hookAPI();
```

### What's currently possible?
The API provided by this library currently only supports a few things:
- You can fetch all people that you're in a lobby with (even in ranked lobbies where names are hidden): `LeagueClient#getParticipants`
- You can fetch locale data (language, region, etc.): `LeagueClient#getRegionLocale`
- You can fetch your wallet data (RP, blue essence): `LeagueClient#getWallet`
- You can fetch your login session info: `LeagueClient#getSession`
- You can fetch your current summoner data (profile icon id, level, required xp, etc.): `LeagueClient#getCurrentSummoner`
- You can check if your account is eligible for a free riot alias change: `LeagueClient#isEligibleForFreeRiotAlias`
- You can invite people to your current lobby: `LeagueClient#inviteToLobby`
- You can create a new lobby for any active game mode: `LeagueClient#createLobby`
- You can set your Solo & Duo Rank to Challenger (only visible in chat module, not profile): `LeagueClient#fakeRank`

### How do I contribute/find more endpoints?
Easiest way is to use an IFEO debugger to get rid of some of the flags that get applied to the client when it gets started.
Once this is done you can use a tool like Fiddler after enabling HTTPS decryption. If you want to make your own IFEO debugger
I'd recommend to use C# for simplicity, might upload a project for one at a later point. Any implementation you find on GitHub
should work just fine.
67 changes: 67 additions & 0 deletions dependency-reduced-pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>dev.dexuby</groupId>
<artifactId>leagueclient4j</artifactId>
<version>1.0.0</version>
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>org.slf4j</pattern>
<shadedPattern>dev.dexuby.leagueclient4j.external.slf4j</shadedPattern>
</relocation>
<relocation>
<pattern>dev.dexuby.easycommon</pattern>
<shadedPattern>dev.dexuby.leagueclient4j.external.easycommon</shadedPattern>
</relocation>
<relocation>
<pattern>org.intellij</pattern>
<shadedPattern>dev.dexuby.leagueclient4j.external.intellij</shadedPattern>
</relocation>
<relocation>
<pattern>org.jetbrains</pattern>
<shadedPattern>dev.dexuby.leagueclient4j.external.jetbrains</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.gson</pattern>
<shadedPattern>dev.dexuby.leagueclient4j.external.gson</shadedPattern>
</relocation>
</relocations>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>module-info.class</exclude>
<exclude>META-INF/**</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<properties>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
92 changes: 92 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>dev.dexuby</groupId>
<artifactId>leagueclient4j</artifactId>
<version>1.0.0</version>

<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>org.slf4j</pattern>
<shadedPattern>dev.dexuby.leagueclient4j.external.slf4j</shadedPattern>
</relocation>
<relocation>
<pattern>dev.dexuby.easycommon</pattern>
<shadedPattern>dev.dexuby.leagueclient4j.external.easycommon</shadedPattern>
</relocation>
<relocation>
<pattern>org.intellij</pattern>
<shadedPattern>dev.dexuby.leagueclient4j.external.intellij</shadedPattern>
</relocation>
<relocation>
<pattern>org.jetbrains</pattern>
<shadedPattern>dev.dexuby.leagueclient4j.external.jetbrains</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.gson</pattern>
<shadedPattern>dev.dexuby.leagueclient4j.external.gson</shadedPattern>
</relocation>
</relocations>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>module-info.class</exclude>
<exclude>META-INF/**</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>

<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>com.github.dexuby</groupId>
<artifactId>easy-common</artifactId>
<version>1.0.4</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
</dependencies>
</project>
15 changes: 15 additions & 0 deletions src/main/java/dev/dexuby/leagueclient4j/Constants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package dev.dexuby.leagueclient4j;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class Constants {

public static final Logger LOGGER = LoggerFactory.getLogger("leaguebreach");
public static final String LEAGUE_CLIENT_EXECUTABLE = "LeagueClientUx.exe";
public static final Gson GSON = new GsonBuilder()
.create();

}
167 changes: 167 additions & 0 deletions src/main/java/dev/dexuby/leagueclient4j/LeagueClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package dev.dexuby.leagueclient4j;

import dev.dexuby.easycommon.external.jetbrains.annotations.NotNull;
import dev.dexuby.easycommon.external.jetbrains.annotations.Nullable;
import dev.dexuby.leagueclient4j.api.RequestData;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public final class LeagueClient {

private static class LeagueClientSingleton {

private static final LeagueClient INSTANCE = new LeagueClient();

}

private LeagueClient() {

}

/**
* Create a new league client API instance by fetching all the necessary data from the running process.
*
* @return The created league client API instance.
*/

public LeagueClientAPI hookAPI() {

final ProcessHandle processHandle = this.findLeagueProcessHandle();
if (processHandle == null) {
Constants.LOGGER.error("Failed to find LeagueClientUx.exe");
return null;
}

final String commandLine = this.getCommandLine(processHandle).orElse(null);
if (commandLine == null) {
Constants.LOGGER.error("Failed to fetch command line.");
return null;
}

final Map<String, String> arguments = this.extractArguments(commandLine);
final String riotPort = arguments.get("--riotclient-app-port");
final String riotToken = Base64.getEncoder().encodeToString(("riot:" + arguments.get("--riotclient-auth-token")).getBytes(StandardCharsets.ISO_8859_1));
final String clientPort = arguments.get("--app-port");
final String clientToken = Base64.getEncoder().encodeToString(("riot:" + arguments.get("--remoting-auth-token")).getBytes(StandardCharsets.ISO_8859_1));

return new LeagueClientAPI(new RequestData(riotPort, riotToken, clientPort, clientToken));

}

/**
* Find the league client process handle.
*
* @return The process handle or <code>null</code>.
*/

@Nullable
private ProcessHandle findLeagueProcessHandle() {

return ProcessHandle.allProcesses()
.filter(handle -> handle.info().command().orElse("").endsWith(Constants.LEAGUE_CLIENT_EXECUTABLE))
.findFirst()
.orElse(null);

}

/**
* Get command line on windows.
*
* @param processHandle The process handle.
* @return Optional containing the command line or nothing if not found.
*/

private Optional<String> getCommandLine(@NotNull final ProcessHandle processHandle) {

if (!this.isWindows())
return processHandle.info().commandLine();

try {
final Process process = new ProcessBuilder("wmic", "process", "where", "ProcessID=" + processHandle.pid(), "get",
"commandline", "/format:list").
redirectErrorStream(true).
start();
try (final InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream());
final BufferedReader reader = new BufferedReader(inputStreamReader)) {
while (true) {
final String line = reader.readLine();
if (line == null)
return Optional.empty();
if (!line.startsWith("CommandLine="))
continue;
return Optional.of(line.substring("CommandLine=".length()));
}
}
} catch (final IOException ex) {
Constants.LOGGER.error("Failed to fetch command line:", ex);
return Optional.empty();
}

}

/**
* Extracts all arguments from the provided command line.
*
* @param commandLine The command line.
* @return The extracted arguments as a map.
*/

private Map<String, String> extractArguments(@NotNull final String commandLine) {

final Map<String, String> arguments = new HashMap<>();
final StringBuilder stringBuilder = new StringBuilder();
boolean read = false;
for (final char c : commandLine.toCharArray()) {
if (c == '"') {
if (read) {
read = false;
final String argument = stringBuilder.toString();
final int firstIndex = argument.indexOf('=');
if (firstIndex != -1)
arguments.put(argument.substring(0, firstIndex), argument.substring(firstIndex + 1));
stringBuilder.setLength(0);
} else {
read = true;
}
} else {
if (read)
stringBuilder.append(c);
}
}

return arguments;

}

/**
* Determines if the program is running on Windows.
*
* @return <code>true</code> if it's running on Windows, <code>false</code> otherwise.
*/

private boolean isWindows() {

return System.getProperty("os.name").startsWith("Windows");

}

/**
* Returns the singleton instance.
*
* @return The singleton instance.
*/

public static LeagueClient getInstance() {

return LeagueClientSingleton.INSTANCE;

}

}
Loading

0 comments on commit c7f10f4

Please sign in to comment.