http-service: add account api
This commit is contained in:
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.http.api.account;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class LoginResponse
|
||||||
|
{
|
||||||
|
private String oauthUrl;
|
||||||
|
private UUID uid;
|
||||||
|
|
||||||
|
public String getOauthUrl()
|
||||||
|
{
|
||||||
|
return oauthUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOauthUrl(String oauthUrl)
|
||||||
|
{
|
||||||
|
this.oauthUrl = oauthUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getUid()
|
||||||
|
{
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUid(UUID uid)
|
||||||
|
{
|
||||||
|
this.uid = uid;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -80,6 +80,11 @@
|
|||||||
<version>1.0.0</version>
|
<version>1.0.0</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.scribejava</groupId>
|
||||||
|
<artifactId>scribejava-apis</artifactId>
|
||||||
|
<version>4.1.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
@@ -114,6 +119,8 @@
|
|||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
<finalName>runelite-${project.version}</finalName>
|
||||||
|
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.tomcat.maven</groupId>
|
<groupId>org.apache.tomcat.maven</groupId>
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.http.service;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.time.Instant;
|
||||||
|
import org.sql2o.converters.Converter;
|
||||||
|
import org.sql2o.converters.ConverterException;
|
||||||
|
|
||||||
|
public class InstantConverter implements Converter<Instant>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Instant convert(Object val) throws ConverterException
|
||||||
|
{
|
||||||
|
Timestamp ts = (Timestamp) val;
|
||||||
|
return ts.toInstant();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object toDatabaseParam(Instant val)
|
||||||
|
{
|
||||||
|
return Timestamp.from(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -27,6 +27,8 @@ package net.runelite.http.service;
|
|||||||
import com.google.inject.Guice;
|
import com.google.inject.Guice;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import net.runelite.http.api.RuneliteAPI;
|
import net.runelite.http.api.RuneliteAPI;
|
||||||
|
import net.runelite.http.service.account.AccountService;
|
||||||
|
import net.runelite.http.service.account.AuthFilter;
|
||||||
import net.runelite.http.service.hiscore.HiscoreService;
|
import net.runelite.http.service.hiscore.HiscoreService;
|
||||||
import net.runelite.http.service.updatecheck.UpdateCheckService;
|
import net.runelite.http.service.updatecheck.UpdateCheckService;
|
||||||
import net.runelite.http.service.worlds.WorldsService;
|
import net.runelite.http.service.worlds.WorldsService;
|
||||||
@@ -42,6 +44,12 @@ public class Service implements SparkApplication
|
|||||||
|
|
||||||
private final JsonTransformer transformer = new JsonTransformer();
|
private final JsonTransformer transformer = new JsonTransformer();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private AuthFilter authFilter;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private AccountService accounts;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private HiscoreService hiscores;
|
private HiscoreService hiscores;
|
||||||
|
|
||||||
@@ -64,6 +72,7 @@ public class Service implements SparkApplication
|
|||||||
public void setupRoutes()
|
public void setupRoutes()
|
||||||
{
|
{
|
||||||
xtea.init();
|
xtea.init();
|
||||||
|
accounts.init();
|
||||||
|
|
||||||
get("/version", (request, response) -> RuneliteAPI.getVersion());
|
get("/version", (request, response) -> RuneliteAPI.getVersion());
|
||||||
get("/update-check", updateCheck::check, transformer);
|
get("/update-check", updateCheck::check, transformer);
|
||||||
@@ -71,6 +80,14 @@ public class Service implements SparkApplication
|
|||||||
get("/worlds", (request, response) -> worlds.listWorlds(), transformer);
|
get("/worlds", (request, response) -> worlds.listWorlds(), transformer);
|
||||||
post("/xtea", xtea::submit);
|
post("/xtea", xtea::submit);
|
||||||
get("/xtea/:rev", xtea::get, transformer);
|
get("/xtea/:rev", xtea::get, transformer);
|
||||||
|
path("/account", () ->
|
||||||
|
{
|
||||||
|
get("/login", accounts::login, transformer);
|
||||||
|
get("/callback", accounts::callback);
|
||||||
|
|
||||||
|
before("/logout", authFilter);
|
||||||
|
get("/logout", accounts::logout);
|
||||||
|
});
|
||||||
|
|
||||||
exception(Exception.class, (exception, request, response) -> logger.warn(null, exception));
|
exception(Exception.class, (exception, request, response) -> logger.warn(null, exception));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,14 +27,22 @@ package net.runelite.http.service;
|
|||||||
import com.google.inject.AbstractModule;
|
import com.google.inject.AbstractModule;
|
||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
import com.google.inject.name.Named;
|
import com.google.inject.name.Named;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import javax.naming.Context;
|
import javax.naming.Context;
|
||||||
import javax.naming.InitialContext;
|
import javax.naming.InitialContext;
|
||||||
import javax.naming.NamingException;
|
import javax.naming.NamingException;
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
import net.runelite.http.service.account.AccountService;
|
||||||
|
import net.runelite.http.service.account.AuthFilter;
|
||||||
import net.runelite.http.service.hiscore.HiscoreService;
|
import net.runelite.http.service.hiscore.HiscoreService;
|
||||||
import net.runelite.http.service.updatecheck.UpdateCheckService;
|
import net.runelite.http.service.updatecheck.UpdateCheckService;
|
||||||
import net.runelite.http.service.worlds.WorldsService;
|
import net.runelite.http.service.worlds.WorldsService;
|
||||||
import net.runelite.http.service.xtea.XteaService;
|
import net.runelite.http.service.xtea.XteaService;
|
||||||
|
import org.sql2o.Sql2o;
|
||||||
|
import org.sql2o.converters.Converter;
|
||||||
|
import org.sql2o.quirks.NoQuirks;
|
||||||
|
|
||||||
public class ServiceModule extends AbstractModule
|
public class ServiceModule extends AbstractModule
|
||||||
{
|
{
|
||||||
@@ -45,17 +53,56 @@ public class ServiceModule extends AbstractModule
|
|||||||
this.service = service;
|
this.service = service;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Context getContext() throws NamingException
|
||||||
|
{
|
||||||
|
Context initCtx = new InitialContext();
|
||||||
|
return (Context) initCtx.lookup("java:comp/env");
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Named("Runelite JDBC")
|
@Named("Runelite JDBC")
|
||||||
DataSource provideDataSource()
|
DataSource provideDataSource()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// It is difficult to inject things into Spark
|
return (DataSource) getContext().lookup("jdbc/runelite");
|
||||||
Context initCtx = new InitialContext();
|
}
|
||||||
Context envCtx = (Context) initCtx.lookup("java:comp/env");
|
catch (NamingException ex)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (DataSource) envCtx.lookup("jdbc/runelite");
|
@Provides
|
||||||
|
@Named("Runelite SQL2O")
|
||||||
|
Sql2o provideSql2o(@Named("Runelite JDBC") DataSource datasource)
|
||||||
|
{
|
||||||
|
Map<Class, Converter> converters = new HashMap<>();
|
||||||
|
converters.put(Instant.class, new InstantConverter());
|
||||||
|
return new Sql2o(datasource, new NoQuirks(converters));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Named("OAuth Client ID")
|
||||||
|
String provideOAuthClientID()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return (String) getContext().lookup("runelite-oauth-client-id");
|
||||||
|
}
|
||||||
|
catch (NamingException ex)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Named("OAuth Client Secret")
|
||||||
|
String provideOAuthClientSecret()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return (String) getContext().lookup("runelite-oauth-client-secret");
|
||||||
}
|
}
|
||||||
catch (NamingException ex)
|
catch (NamingException ex)
|
||||||
{
|
{
|
||||||
@@ -68,6 +115,9 @@ public class ServiceModule extends AbstractModule
|
|||||||
{
|
{
|
||||||
bind(Service.class).toInstance(service);
|
bind(Service.class).toInstance(service);
|
||||||
|
|
||||||
|
bind(AuthFilter.class);
|
||||||
|
|
||||||
|
bind(AccountService.class);
|
||||||
bind(HiscoreService.class);
|
bind(HiscoreService.class);
|
||||||
bind(UpdateCheckService.class);
|
bind(UpdateCheckService.class);
|
||||||
bind(WorldsService.class);
|
bind(WorldsService.class);
|
||||||
|
|||||||
@@ -0,0 +1,227 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.http.service.account;
|
||||||
|
|
||||||
|
import net.runelite.http.service.account.beans.UserEntry;
|
||||||
|
import net.runelite.http.service.account.beans.SessionEntry;
|
||||||
|
import com.github.scribejava.apis.GoogleApi20;
|
||||||
|
import com.github.scribejava.core.builder.ServiceBuilder;
|
||||||
|
import com.github.scribejava.core.model.OAuth2AccessToken;
|
||||||
|
import com.github.scribejava.core.model.OAuthRequest;
|
||||||
|
import com.github.scribejava.core.model.Verb;
|
||||||
|
import com.github.scribejava.core.oauth.OAuth20Service;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.name.Named;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import net.runelite.http.api.RuneliteAPI;
|
||||||
|
import net.runelite.http.api.account.LoginResponse;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.sql2o.Connection;
|
||||||
|
import org.sql2o.Sql2o;
|
||||||
|
import org.sql2o.Sql2oException;
|
||||||
|
import spark.Request;
|
||||||
|
import spark.Response;
|
||||||
|
|
||||||
|
public class AccountService
|
||||||
|
{
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(AccountService.class);
|
||||||
|
|
||||||
|
private static final String CREATE_SESSIONS = "CREATE TABLE IF NOT EXISTS `sessions` (\n"
|
||||||
|
+ " `user` int(11) NOT NULL,\n"
|
||||||
|
+ " `uuid` varchar(36) NOT NULL,\n"
|
||||||
|
+ " `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n"
|
||||||
|
+ " `last_used` timestamp NOT NULL,\n"
|
||||||
|
+ " UNIQUE KEY `user_2` (`user`,`uuid`),\n"
|
||||||
|
+ " KEY `user` (`user`)\n"
|
||||||
|
+ ") ENGINE=InnoDB";
|
||||||
|
|
||||||
|
private static final String CREATE_USERS = "CREATE TABLE IF NOT EXISTS `users` (\n"
|
||||||
|
+ " `id` int(11) NOT NULL,\n"
|
||||||
|
+ " `username` tinytext NOT NULL,\n"
|
||||||
|
+ " `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n"
|
||||||
|
+ " PRIMARY KEY (`id`),\n"
|
||||||
|
+ " UNIQUE KEY `username` (`username`(64))\n"
|
||||||
|
+ ") ENGINE=InnoDB";
|
||||||
|
|
||||||
|
private static final String SESSIONS_FK = "ALTER TABLE `sessions`\n"
|
||||||
|
+ " ADD CONSTRAINT `id` FOREIGN KEY (`user`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;";
|
||||||
|
|
||||||
|
private static final String SCOPE = "https://www.googleapis.com/auth/userinfo.email";
|
||||||
|
private static final String USERINFO = "https://www.googleapis.com/oauth2/v2/userinfo";
|
||||||
|
private static final String RL_OAUTH_URL = "https://api.runelite.net/oauth/";
|
||||||
|
private static final String RL_REDIR = "http://runelite.net/logged-in";
|
||||||
|
|
||||||
|
private final Gson gson = new Gson();
|
||||||
|
|
||||||
|
private final Sql2o sql2o;
|
||||||
|
private final String oauthClientId;
|
||||||
|
private final String oauthClientSecret;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public AccountService(
|
||||||
|
@Named("Runelite SQL2O") Sql2o sql2o,
|
||||||
|
@Named("OAuth Client ID") String oauthClientId,
|
||||||
|
@Named("OAuth Client Secret") String oauthClientSecret
|
||||||
|
)
|
||||||
|
{
|
||||||
|
this.sql2o = sql2o;
|
||||||
|
this.oauthClientId = oauthClientId;
|
||||||
|
this.oauthClientSecret = oauthClientSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init()
|
||||||
|
{
|
||||||
|
try (Connection con = sql2o.beginTransaction())
|
||||||
|
{
|
||||||
|
con.createQuery(CREATE_SESSIONS)
|
||||||
|
.executeUpdate();
|
||||||
|
|
||||||
|
con.createQuery(CREATE_USERS)
|
||||||
|
.executeUpdate();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
con.createQuery(SESSIONS_FK)
|
||||||
|
.executeUpdate();
|
||||||
|
}
|
||||||
|
catch (Sql2oException ex)
|
||||||
|
{
|
||||||
|
// Ignore, happens when index already exists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoginResponse login(Request request, Response response)
|
||||||
|
{
|
||||||
|
UUID uuid = UUID.randomUUID();
|
||||||
|
|
||||||
|
State state = new State();
|
||||||
|
state.setUuid(uuid);
|
||||||
|
state.setApiVersion(RuneliteAPI.getVersion());
|
||||||
|
|
||||||
|
OAuth20Service service = new ServiceBuilder()
|
||||||
|
.apiKey(oauthClientId)
|
||||||
|
.apiSecret(oauthClientSecret)
|
||||||
|
.scope(SCOPE)
|
||||||
|
.callback(RL_OAUTH_URL)
|
||||||
|
.state(gson.toJson(state))
|
||||||
|
.build(GoogleApi20.instance());
|
||||||
|
|
||||||
|
String authorizationUrl = service.getAuthorizationUrl();
|
||||||
|
|
||||||
|
LoginResponse lr = new LoginResponse();
|
||||||
|
lr.setOauthUrl(authorizationUrl);
|
||||||
|
lr.setUid(uuid);
|
||||||
|
|
||||||
|
return lr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object callback(Request request, Response response) throws IOException, InterruptedException, ExecutionException
|
||||||
|
{
|
||||||
|
String error = request.queryParams("error");
|
||||||
|
|
||||||
|
if (error != null)
|
||||||
|
{
|
||||||
|
logger.info("Error in oauth callback: {}", error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String authorizationCode = request.queryParams("code");
|
||||||
|
State state = gson.fromJson(request.queryParams("state"), State.class);
|
||||||
|
|
||||||
|
logger.info("Got authorization code {} for uuid {}", authorizationCode, state.getUuid());
|
||||||
|
|
||||||
|
OAuth20Service service = new ServiceBuilder()
|
||||||
|
.apiKey(oauthClientId)
|
||||||
|
.apiSecret(oauthClientSecret)
|
||||||
|
.scope(SCOPE)
|
||||||
|
.callback(RL_OAUTH_URL)
|
||||||
|
.state(gson.toJson(state))
|
||||||
|
.build(GoogleApi20.instance());
|
||||||
|
|
||||||
|
OAuth2AccessToken accessToken = service.getAccessToken(authorizationCode);
|
||||||
|
|
||||||
|
// Access user info
|
||||||
|
OAuthRequest orequest = new OAuthRequest(Verb.GET, USERINFO);
|
||||||
|
service.signRequest(accessToken, orequest);
|
||||||
|
|
||||||
|
com.github.scribejava.core.model.Response oresponse = service.execute(orequest);
|
||||||
|
|
||||||
|
if (oresponse.getCode() / 100 != 2)
|
||||||
|
{
|
||||||
|
// Could be a forged result
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserInfo userInfo = gson.fromJson(oresponse.getBody(), UserInfo.class);
|
||||||
|
|
||||||
|
logger.info("Got user info: {}", userInfo);
|
||||||
|
|
||||||
|
try (Connection con = sql2o.open())
|
||||||
|
{
|
||||||
|
con.createQuery("insert ignore into users (username) values (:username)")
|
||||||
|
.addParameter("username", userInfo.getEmail())
|
||||||
|
.executeUpdate();
|
||||||
|
|
||||||
|
UserEntry user = con.createQuery("select id from users where username = :username")
|
||||||
|
.addParameter("username", userInfo.getEmail())
|
||||||
|
.executeAndFetchFirst(UserEntry.class);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return null; // that's weird
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert session
|
||||||
|
con.createQuery("insert ignore into sessions (user, uuid) values (:user, :uuid)")
|
||||||
|
.addParameter("user", user.getId())
|
||||||
|
.addParameter("uuid", state.getUuid().toString())
|
||||||
|
.executeUpdate();
|
||||||
|
|
||||||
|
logger.info("Created session for user {}", user.getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
response.redirect(RL_REDIR);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object logout(Request request, Response response)
|
||||||
|
{
|
||||||
|
SessionEntry session = request.session().attribute("session");
|
||||||
|
|
||||||
|
try (Connection con = sql2o.open())
|
||||||
|
{
|
||||||
|
con.createQuery("delete from sessions where uuid = :uuid")
|
||||||
|
.addParameter("uuid", session.getUuid().toString())
|
||||||
|
.executeUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.http.service.account;
|
||||||
|
|
||||||
|
import net.runelite.http.service.account.beans.SessionEntry;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.name.Named;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.sql2o.Connection;
|
||||||
|
import org.sql2o.Sql2o;
|
||||||
|
import spark.Filter;
|
||||||
|
import spark.Request;
|
||||||
|
import spark.Response;
|
||||||
|
import spark.Session;
|
||||||
|
import static spark.Spark.halt;
|
||||||
|
|
||||||
|
public class AuthFilter implements Filter
|
||||||
|
{
|
||||||
|
private static final String RUNELITE_AUTH = "RUNELITE-AUTH";
|
||||||
|
|
||||||
|
private final Sql2o sql2o;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public AuthFilter(@Named("Runelite SQL2O") Sql2o sql2o)
|
||||||
|
{
|
||||||
|
this.sql2o = sql2o;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(Request request, Response response) throws Exception
|
||||||
|
{
|
||||||
|
String runeliteAuth = request.headers(RUNELITE_AUTH);
|
||||||
|
if (runeliteAuth == null)
|
||||||
|
{
|
||||||
|
halt(401, "Access denied");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UUID uuid = UUID.fromString(runeliteAuth);
|
||||||
|
|
||||||
|
try (Connection con = sql2o.open())
|
||||||
|
{
|
||||||
|
SessionEntry sessionEntry = con.createQuery("select user, uuid, created from sessions where uuid = :uuid")
|
||||||
|
.addParameter("uuid", uuid.toString())
|
||||||
|
.executeAndFetchFirst(SessionEntry.class);
|
||||||
|
|
||||||
|
if (sessionEntry == null)
|
||||||
|
{
|
||||||
|
halt(401, "Access denied");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Instant now = Instant.now();
|
||||||
|
|
||||||
|
con.createQuery("update sessions set last_used = :last_used where uuid = :uuid")
|
||||||
|
.addParameter("last_used", Timestamp.from(now))
|
||||||
|
.addParameter("uuid", uuid.toString())
|
||||||
|
.executeUpdate();
|
||||||
|
|
||||||
|
sessionEntry.setLastUsed(now);
|
||||||
|
|
||||||
|
Session session = request.session();
|
||||||
|
session.attribute("session", sessionEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.http.service.account;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class State
|
||||||
|
{
|
||||||
|
private UUID uuid;
|
||||||
|
private String apiVersion;
|
||||||
|
|
||||||
|
public UUID getUuid()
|
||||||
|
{
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUuid(UUID uuid)
|
||||||
|
{
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApiVersion()
|
||||||
|
{
|
||||||
|
return apiVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApiVersion(String apiVersion)
|
||||||
|
{
|
||||||
|
this.apiVersion = apiVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.http.service.account;
|
||||||
|
|
||||||
|
public class UserInfo
|
||||||
|
{
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "UserInfo{" + "email=" + email + '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail()
|
||||||
|
{
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email)
|
||||||
|
{
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.http.service.account.beans;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class SessionEntry
|
||||||
|
{
|
||||||
|
private int user;
|
||||||
|
private UUID uuid;
|
||||||
|
private Instant created;
|
||||||
|
private Instant lastUsed;
|
||||||
|
|
||||||
|
public int getUser()
|
||||||
|
{
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUser(int user)
|
||||||
|
{
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getUuid()
|
||||||
|
{
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUuid(UUID uuid)
|
||||||
|
{
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Instant getCreated()
|
||||||
|
{
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreated(Instant created)
|
||||||
|
{
|
||||||
|
this.created = created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Instant getLastUsed()
|
||||||
|
{
|
||||||
|
return lastUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastUsed(Instant lastUsed)
|
||||||
|
{
|
||||||
|
this.lastUsed = lastUsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package net.runelite.http.service.account.beans;
|
||||||
|
|
||||||
|
public class UserEntry
|
||||||
|
{
|
||||||
|
private int id;
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "UserEntry{" + "id=" + id + ", username=" + username + '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(int id)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername()
|
||||||
|
{
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username)
|
||||||
|
{
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,7 +29,6 @@ import com.google.inject.Inject;
|
|||||||
import com.google.inject.name.Named;
|
import com.google.inject.name.Named;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.sql.DataSource;
|
|
||||||
import net.runelite.http.api.xtea.XteaKey;
|
import net.runelite.http.api.xtea.XteaKey;
|
||||||
import net.runelite.http.api.xtea.XteaRequest;
|
import net.runelite.http.api.xtea.XteaRequest;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -54,20 +53,17 @@ public class XteaService
|
|||||||
+ " PRIMARY KEY (`rev`,`region`,`key1`,`key2`,`key3`,`key4`)\n"
|
+ " PRIMARY KEY (`rev`,`region`,`key1`,`key2`,`key3`,`key4`)\n"
|
||||||
+ ") ENGINE=InnoDB;";
|
+ ") ENGINE=InnoDB;";
|
||||||
|
|
||||||
|
private final Sql2o sql2o;
|
||||||
private final DataSource datasource;
|
|
||||||
private final Gson gson = new Gson();
|
private final Gson gson = new Gson();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public XteaService(@Named("Runelite JDBC") DataSource datasource)
|
public XteaService(@Named("Runelite SQL2O") Sql2o sql2o)
|
||||||
{
|
{
|
||||||
this.datasource = datasource;
|
this.sql2o = sql2o;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init()
|
public void init()
|
||||||
{
|
{
|
||||||
Sql2o sql2o = new Sql2o(datasource);
|
|
||||||
|
|
||||||
try (Connection con = sql2o.beginTransaction())
|
try (Connection con = sql2o.beginTransaction())
|
||||||
{
|
{
|
||||||
con.createQuery(CREATE_SQL)
|
con.createQuery(CREATE_SQL)
|
||||||
@@ -79,8 +75,6 @@ public class XteaService
|
|||||||
{
|
{
|
||||||
XteaRequest xteaRequest = gson.fromJson(request.body(), XteaRequest.class);
|
XteaRequest xteaRequest = gson.fromJson(request.body(), XteaRequest.class);
|
||||||
|
|
||||||
Sql2o sql2o = new Sql2o(datasource);
|
|
||||||
|
|
||||||
try (Connection con = sql2o.beginTransaction())
|
try (Connection con = sql2o.beginTransaction())
|
||||||
{
|
{
|
||||||
Query query = con.createQuery("insert ignore into xtea (rev, region, key1, key2, key3, key4) values (:rev, :region, :key1, :key2, :key3, :key4)");
|
Query query = con.createQuery("insert ignore into xtea (rev, region, key1, key2, key3, key4) values (:rev, :region, :key1, :key2, :key3, :key4)");
|
||||||
@@ -108,8 +102,6 @@ public class XteaService
|
|||||||
String revStr = request.params("rev");
|
String revStr = request.params("rev");
|
||||||
int revision = Integer.parseInt(revStr);
|
int revision = Integer.parseInt(revStr);
|
||||||
|
|
||||||
Sql2o sql2o = new Sql2o(datasource);
|
|
||||||
|
|
||||||
try (Connection con = sql2o.open())
|
try (Connection con = sql2o.open())
|
||||||
{
|
{
|
||||||
List<XteaEntry> entries = con.createQuery("select * from xtea where rev = :rev")
|
List<XteaEntry> entries = con.createQuery("select * from xtea where rev = :rev")
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ import java.io.InputStreamReader;
|
|||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
import javax.sql.DataSource;
|
|
||||||
import net.runelite.http.api.hiscore.HiscoreResult;
|
import net.runelite.http.api.hiscore.HiscoreResult;
|
||||||
import net.runelite.http.api.hiscore.Skill;
|
import net.runelite.http.api.hiscore.Skill;
|
||||||
import net.runelite.http.service.hiscore.HiscoreService;
|
import net.runelite.http.service.hiscore.HiscoreService;
|
||||||
@@ -48,23 +47,32 @@ import org.mockito.Mock;
|
|||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.sql2o.Sql2o;
|
||||||
import spark.Spark;
|
import spark.Spark;
|
||||||
|
|
||||||
public class ServiceTest
|
public class ServiceTest
|
||||||
{
|
{
|
||||||
private static final String URL_BASE = "http://localhost:4567";
|
private static final String URL_BASE = "http://localhost:4567";
|
||||||
|
|
||||||
private Service service;
|
private Service service;
|
||||||
|
|
||||||
@Bind
|
@Bind
|
||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
@Named("Runelite JDBC")
|
@Named("Runelite SQL2O")
|
||||||
private DataSource dataSource;
|
private Sql2o sql2o;
|
||||||
|
|
||||||
|
@Bind
|
||||||
|
@Named("OAuth Client ID")
|
||||||
|
private String clientId = "test";
|
||||||
|
|
||||||
|
@Bind
|
||||||
|
@Named("OAuth Client Secret")
|
||||||
|
private String clientSecret = "test";
|
||||||
|
|
||||||
@Bind
|
@Bind
|
||||||
@Mock
|
@Mock
|
||||||
private HiscoreService hiscoreService;
|
private HiscoreService hiscoreService;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void before()
|
public void before()
|
||||||
{
|
{
|
||||||
@@ -73,38 +81,38 @@ public class ServiceTest
|
|||||||
// Inject everything in the test object
|
// Inject everything in the test object
|
||||||
Injector injector = Guice.createInjector(BoundFieldModule.of(this));
|
Injector injector = Guice.createInjector(BoundFieldModule.of(this));
|
||||||
injector.injectMembers(this);
|
injector.injectMembers(this);
|
||||||
|
|
||||||
ServletContextLogger.setServletContext(mock(ServletContext.class));
|
ServletContextLogger.setServletContext(mock(ServletContext.class));
|
||||||
|
|
||||||
service = injector.getInstance(Service.class);
|
service = injector.getInstance(Service.class);
|
||||||
service.setupRoutes();
|
service.setupRoutes();
|
||||||
|
|
||||||
Spark.awaitInitialization();
|
Spark.awaitInitialization();
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void after()
|
public void after()
|
||||||
{
|
{
|
||||||
Spark.stop();
|
Spark.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInit() throws Exception
|
public void testInit() throws Exception
|
||||||
{
|
{
|
||||||
HiscoreResult result = new HiscoreResult();
|
HiscoreResult result = new HiscoreResult();
|
||||||
result.setAttack(new Skill(1, 99, 42));
|
result.setAttack(new Skill(1, 99, 42));
|
||||||
|
|
||||||
when(hiscoreService.lookup("zezima")).thenReturn(result);
|
when(hiscoreService.lookup("zezima")).thenReturn(result);
|
||||||
|
|
||||||
URL url = new URL(URL_BASE + "/hiscore?username=zezima");
|
URL url = new URL(URL_BASE + "/hiscore?username=zezima");
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
connection.setRequestMethod("GET");
|
connection.setRequestMethod("GET");
|
||||||
connection.connect();
|
connection.connect();
|
||||||
|
|
||||||
Gson gson = new Gson();
|
Gson gson = new Gson();
|
||||||
HiscoreResult res = gson.fromJson(new InputStreamReader(connection.getInputStream()), HiscoreResult.class);
|
HiscoreResult res = gson.fromJson(new InputStreamReader(connection.getInputStream()), HiscoreResult.class);
|
||||||
|
|
||||||
Assert.assertEquals(result, res);
|
Assert.assertEquals(result, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user