diff --git a/runelite-client/src/main/java/net/runelite/client/account/AccountClient.java b/runelite-client/src/main/java/net/runelite/client/account/AccountClient.java index 4c26a60170..6cacaafccc 100644 --- a/runelite-client/src/main/java/net/runelite/client/account/AccountClient.java +++ b/runelite-client/src/main/java/net/runelite/client/account/AccountClient.java @@ -57,12 +57,12 @@ public class AccountClient this.apiBase = apiBase; } - public OAuthResponse login() throws IOException + public OAuthResponse login(int port) throws IOException { HttpUrl url = apiBase.newBuilder() .addPathSegment("account") .addPathSegment("login") - .addQueryParameter("uuid", uuid.toString()) + .addQueryParameter("port", Integer.toString(port)) .build(); log.debug("Built URI: {}", url); diff --git a/runelite-client/src/main/java/net/runelite/client/account/AccountSession.java b/runelite-client/src/main/java/net/runelite/client/account/AccountSession.java index dc1534ab94..c50b5720f4 100644 --- a/runelite-client/src/main/java/net/runelite/client/account/AccountSession.java +++ b/runelite-client/src/main/java/net/runelite/client/account/AccountSession.java @@ -35,5 +35,5 @@ public class AccountSession { private final UUID uuid; private final Instant created; - private String username; + private final String username; } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java b/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java index 81f08dd3e6..04d264ef5b 100644 --- a/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java +++ b/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java @@ -25,12 +25,14 @@ package net.runelite.client.account; import com.google.gson.Gson; +import com.sun.net.httpserver.HttpServer; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Writer; +import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.time.Instant; @@ -42,13 +44,11 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.EventBus; -import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.SessionClose; import net.runelite.client.events.SessionOpen; import net.runelite.client.util.LinkBrowser; -import net.runelite.client.ws.WSClient; import net.runelite.http.api.account.OAuthResponse; -import net.runelite.http.api.ws.messages.LoginResponse; +import okhttp3.HttpUrl; @Singleton @Slf4j @@ -59,26 +59,29 @@ public class SessionManager private final EventBus eventBus; private final ConfigManager configManager; - private final WSClient wsClient; private final File sessionFile; private final AccountClient accountClient; private final Gson gson; + private final String oauthRedirect; + + private HttpServer server; @Inject private SessionManager( @Named("sessionfile") File sessionfile, ConfigManager configManager, EventBus eventBus, - WSClient wsClient, AccountClient accountClient, - Gson gson) + Gson gson, + @Named("runelite.oauth.redirect") String oauthRedirect + ) { this.configManager = configManager; this.eventBus = eventBus; - this.wsClient = wsClient; this.sessionFile = sessionfile; this.accountClient = accountClient; this.gson = gson; + this.oauthRedirect = oauthRedirect; eventBus.register(this); } @@ -113,7 +116,7 @@ public class SessionManager return; } - openSession(session, false); + openSession(session); } private void saveSession() @@ -141,19 +144,12 @@ public class SessionManager } /** - * Set the given session as the active session and open a socket to the - * server with the given session + * Set the given session as the active session * * @param session session */ - private void openSession(AccountSession session, boolean openSocket) + private void openSession(AccountSession session) { - // Change session on the websocket - if (openSocket) - { - wsClient.changeSession(session.getUuid()); - } - accountSession = session; if (session.getUsername() != null) @@ -168,8 +164,6 @@ public class SessionManager private void closeSession() { - wsClient.changeSession(null); - if (accountSession == null) { return; @@ -197,49 +191,85 @@ public class SessionManager public void login() { - // If a session is already open, use that id. Otherwise generate a new id. - UUID uuid = wsClient.getSessionId() != null ? wsClient.getSessionId() : UUID.randomUUID(); - accountClient.setUuid(uuid); + if (server == null) + { + try + { + startServer(); + } + catch (IOException ex) + { + log.error("Unable to start http server", ex); + return; + } + } final OAuthResponse login; try { - login = accountClient.login(); + login = accountClient.login(server.getAddress().getPort()); } catch (IOException ex) { - log.warn("Unable to get oauth url", ex); + log.error("Unable to get oauth url", ex); return; } - // Create new session - openSession(new AccountSession(login.getUid(), Instant.now()), true); - // Navigate to login link LinkBrowser.browse(login.getOauthUrl()); } - @Subscribe - public void onLoginResponse(LoginResponse loginResponse) - { - log.debug("Now signed in as {}", loginResponse.getUsername()); - - AccountSession session = getAccountSession(); - session.setUsername(loginResponse.getUsername()); - - // Open session, again, now that we have a username - // This triggers onSessionOpen - // The socket is already opened here anyway so we pass true for openSocket - openSession(session, true); - - // Save session to disk - saveSession(); - } - public void logout() { closeSession(); deleteSession(); } + + private void startServer() throws IOException + { + server = HttpServer.create(new InetSocketAddress("localhost", 0), 1); + server.createContext("/oauth", req -> + { + try + { + final HttpUrl url = HttpUrl.get("http://localhost" + req.getRequestURI()); + final String username = url.queryParameter("username"); + final UUID sessionId = UUID.fromString(url.queryParameter("sessionId")); + + log.debug("Now signed in as {}", username); + + // open the session, which triggers the sessonopen event + AccountSession session = new AccountSession(sessionId, Instant.now(), username); + openSession(session); + + // Save session to disk + saveSession(); + + req.getResponseHeaders().set("Location", oauthRedirect); + req.sendResponseHeaders(302, 0); + } + catch (Exception e) + { + log.warn("failure serving oauth response", e); + req.sendResponseHeaders(400, 0); + req.getResponseBody().write(e.getMessage().getBytes(StandardCharsets.UTF_8)); + } + finally + { + req.close(); + stopServer(); + } + }); + + log.debug("Starting server {}", server); + server.start(); + } + + private void stopServer() + { + log.debug("Stopping server {}", server); + server.stop(0); + server = null; + } } diff --git a/runelite-client/src/main/resources/net/runelite/client/runelite.properties b/runelite-client/src/main/resources/net/runelite/client/runelite.properties index 601193633f..892e84181f 100644 --- a/runelite-client/src/main/resources/net/runelite/client/runelite.properties +++ b/runelite-client/src/main/resources/net/runelite/client/runelite.properties @@ -20,4 +20,5 @@ runelite.session=https://api.runelite.net/session runelite.static.base=https://static.runelite.net runelite.ws=https://api.runelite.net/ws runelite.config=https://static.runelite.net/config.json -runelite.osrstwitter.link=https://twitter.com/OldSchoolRS \ No newline at end of file +runelite.osrstwitter.link=https://twitter.com/OldSchoolRS +runelite.oauth.redirect=https://runelite.net/logged-in \ No newline at end of file diff --git a/runelite-client/src/test/java/net/runelite/client/config/ConfigManagerTest.java b/runelite-client/src/test/java/net/runelite/client/config/ConfigManagerTest.java index 4b46a8844f..b6e86871b7 100644 --- a/runelite-client/src/test/java/net/runelite/client/config/ConfigManagerTest.java +++ b/runelite-client/src/test/java/net/runelite/client/config/ConfigManagerTest.java @@ -29,14 +29,11 @@ import com.google.inject.testing.fieldbinder.Bind; import com.google.inject.testing.fieldbinder.BoundFieldModule; import java.io.File; import java.io.IOException; -import java.time.Instant; -import java.util.UUID; import java.util.concurrent.ScheduledExecutorService; import javax.inject.Inject; import javax.inject.Named; import net.runelite.api.Client; import net.runelite.client.RuneLite; -import net.runelite.client.account.AccountSession; import net.runelite.client.eventbus.EventBus; import org.junit.Assert; import static org.junit.Assert.assertNotNull; @@ -89,9 +86,6 @@ public class ConfigManagerTest @Test public void testGetConfig() throws IOException { - AccountSession accountSession = new AccountSession(UUID.randomUUID(), Instant.now()); - accountSession.setUsername("test"); - manager.setConfiguration("test", "key", "moo"); TestConfig conf = manager.getConfig(TestConfig.class); @@ -101,9 +95,6 @@ public class ConfigManagerTest @Test public void testGetConfigDefault() throws IOException { - AccountSession accountSession = new AccountSession(UUID.randomUUID(), Instant.now()); - accountSession.setUsername("test"); - TestConfig conf = manager.getConfig(TestConfig.class); Assert.assertEquals("default", conf.key()); } @@ -111,9 +102,6 @@ public class ConfigManagerTest @Test public void testSetConfig() throws IOException { - AccountSession accountSession = new AccountSession(UUID.randomUUID(), Instant.now()); - accountSession.setUsername("test"); - TestConfig conf = manager.getConfig(TestConfig.class); conf.key("new value"); @@ -123,9 +111,6 @@ public class ConfigManagerTest @Test public void testGetConfigDescriptor() throws IOException { - AccountSession accountSession = new AccountSession(UUID.randomUUID(), Instant.now()); - accountSession.setUsername("test"); - TestConfig conf = manager.getConfig(TestConfig.class); ConfigDescriptor descriptor = manager.getConfigDescriptor(conf); Assert.assertEquals(2, descriptor.getItems().size());