http-service: add account api

This commit is contained in:
Adam
2017-05-05 23:11:29 -04:00
parent 123336a1ed
commit 7bac276e25
13 changed files with 756 additions and 32 deletions

View File

@@ -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;
}
}

View File

@@ -80,6 +80,11 @@
<version>1.0.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.github.scribejava</groupId>
<artifactId>scribejava-apis</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
@@ -114,6 +119,8 @@
</dependencies>
<build>
<finalName>runelite-${project.version}</finalName>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>

View File

@@ -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);
}
}

View File

@@ -27,6 +27,8 @@ package net.runelite.http.service;
import com.google.inject.Guice;
import com.google.inject.Inject;
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.updatecheck.UpdateCheckService;
import net.runelite.http.service.worlds.WorldsService;
@@ -42,6 +44,12 @@ public class Service implements SparkApplication
private final JsonTransformer transformer = new JsonTransformer();
@Inject
private AuthFilter authFilter;
@Inject
private AccountService accounts;
@Inject
private HiscoreService hiscores;
@@ -64,6 +72,7 @@ public class Service implements SparkApplication
public void setupRoutes()
{
xtea.init();
accounts.init();
get("/version", (request, response) -> RuneliteAPI.getVersion());
get("/update-check", updateCheck::check, transformer);
@@ -71,6 +80,14 @@ public class Service implements SparkApplication
get("/worlds", (request, response) -> worlds.listWorlds(), transformer);
post("/xtea", xtea::submit);
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));
}

View File

@@ -27,14 +27,22 @@ package net.runelite.http.service;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
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.InitialContext;
import javax.naming.NamingException;
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.updatecheck.UpdateCheckService;
import net.runelite.http.service.worlds.WorldsService;
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
{
@@ -45,17 +53,56 @@ public class ServiceModule extends AbstractModule
this.service = service;
}
private Context getContext() throws NamingException
{
Context initCtx = new InitialContext();
return (Context) initCtx.lookup("java:comp/env");
}
@Provides
@Named("Runelite JDBC")
DataSource provideDataSource()
{
try
{
// It is difficult to inject things into Spark
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
return (DataSource) getContext().lookup("jdbc/runelite");
}
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)
{
@@ -68,6 +115,9 @@ public class ServiceModule extends AbstractModule
{
bind(Service.class).toInstance(service);
bind(AuthFilter.class);
bind(AccountService.class);
bind(HiscoreService.class);
bind(UpdateCheckService.class);
bind(WorldsService.class);

View File

@@ -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 "";
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -29,7 +29,6 @@ import com.google.inject.Inject;
import com.google.inject.name.Named;
import java.util.List;
import java.util.stream.Collectors;
import javax.sql.DataSource;
import net.runelite.http.api.xtea.XteaKey;
import net.runelite.http.api.xtea.XteaRequest;
import org.slf4j.Logger;
@@ -54,20 +53,17 @@ public class XteaService
+ " PRIMARY KEY (`rev`,`region`,`key1`,`key2`,`key3`,`key4`)\n"
+ ") ENGINE=InnoDB;";
private final DataSource datasource;
private final Sql2o sql2o;
private final Gson gson = new Gson();
@Inject
public XteaService(@Named("Runelite JDBC") DataSource datasource)
public XteaService(@Named("Runelite SQL2O") Sql2o sql2o)
{
this.datasource = datasource;
this.sql2o = sql2o;
}
public void init()
{
Sql2o sql2o = new Sql2o(datasource);
try (Connection con = sql2o.beginTransaction())
{
con.createQuery(CREATE_SQL)
@@ -79,8 +75,6 @@ public class XteaService
{
XteaRequest xteaRequest = gson.fromJson(request.body(), XteaRequest.class);
Sql2o sql2o = new Sql2o(datasource);
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)");
@@ -108,8 +102,6 @@ public class XteaService
String revStr = request.params("rev");
int revision = Integer.parseInt(revStr);
Sql2o sql2o = new Sql2o(datasource);
try (Connection con = sql2o.open())
{
List<XteaEntry> entries = con.createQuery("select * from xtea where rev = :rev")

View File

@@ -35,7 +35,6 @@ import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.servlet.ServletContext;
import javax.sql.DataSource;
import net.runelite.http.api.hiscore.HiscoreResult;
import net.runelite.http.api.hiscore.Skill;
import net.runelite.http.service.hiscore.HiscoreService;
@@ -48,6 +47,7 @@ import org.mockito.Mock;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.mockito.MockitoAnnotations;
import org.sql2o.Sql2o;
import spark.Spark;
public class ServiceTest
@@ -58,8 +58,16 @@ public class ServiceTest
@Bind
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
@Named("Runelite JDBC")
private DataSource dataSource;
@Named("Runelite SQL2O")
private Sql2o sql2o;
@Bind
@Named("OAuth Client ID")
private String clientId = "test";
@Bind
@Named("OAuth Client Secret")
private String clientSecret = "test";
@Bind
@Mock