Add user and captcha handling methods
This commit is contained in:
parent
23ac46eee8
commit
69b68ed1e4
9 changed files with 854 additions and 436 deletions
|
@ -8,6 +8,8 @@ import net.nosial.socialclient.exceptions.CryptographyException;
|
|||
import net.nosial.socialclient.exceptions.ResolutionException;
|
||||
import net.nosial.socialclient.exceptions.RpcException;
|
||||
import net.nosial.socialclient.objects.RpcRequest;
|
||||
import net.nosial.socialclient.objects.standard.ImageCaptcha;
|
||||
import net.nosial.socialclient.objects.standard.SelfUser;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.PrivateKey;
|
||||
|
@ -17,8 +19,6 @@ import java.util.Map;
|
|||
|
||||
public class Client extends RpcClient
|
||||
{
|
||||
|
||||
|
||||
public Client(String domain) throws ResolutionException, CryptographyException
|
||||
{
|
||||
super(domain);
|
||||
|
@ -31,7 +31,8 @@ public class Client extends RpcClient
|
|||
|
||||
public String createSession(KeyPair keyPair) throws RpcException
|
||||
{
|
||||
RpcResult response = this.sendRequest(new RpcRequest("create_session", Utilities.randomCrc32(), new HashMap<>(){{
|
||||
RpcResult response = this.sendRequest(new RpcRequest("createSession", Utilities.randomCrc32(), new HashMap<>()
|
||||
{{
|
||||
put("public_key", Cryptography.exportPublicKey(keyPair));
|
||||
}}));
|
||||
|
||||
|
@ -78,4 +79,90 @@ public class Client extends RpcClient
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean register(String username) throws RpcException
|
||||
{
|
||||
RpcResult response = this.sendRequest(new RpcRequest("register", Utilities.randomCrc32(), new HashMap<>()
|
||||
{{
|
||||
put("username", username);
|
||||
}}));
|
||||
|
||||
if(response == null)
|
||||
{
|
||||
throw new RpcException("Response is null");
|
||||
}
|
||||
|
||||
if(!response.isSuccess())
|
||||
{
|
||||
throw new RpcException(response);
|
||||
}
|
||||
|
||||
return (boolean)response.getResponse().getResult();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public SelfUser getMe() throws RpcException
|
||||
{
|
||||
RpcResult response = this.sendRequest(new RpcRequest("getMe", Utilities.randomCrc32()));
|
||||
|
||||
if(response == null)
|
||||
{
|
||||
throw new RpcException("Response is null");
|
||||
}
|
||||
|
||||
if(!response.isSuccess())
|
||||
{
|
||||
throw new RpcException(response);
|
||||
}
|
||||
|
||||
if(response.getResponse().getResult() instanceof Map<?,?>)
|
||||
{
|
||||
return new SelfUser((Map<String, Object>) response.getResponse().getResult());
|
||||
}
|
||||
|
||||
throw new RpcException("Unexpected result type, expected Map<?,?>");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ImageCaptcha verificationGetImageCaptcha() throws RpcException
|
||||
{
|
||||
RpcResult response = this.sendRequest(new RpcRequest("verificationGetImageCaptcha", Utilities.randomCrc32()));
|
||||
|
||||
if(response == null)
|
||||
{
|
||||
throw new RpcException("Response is null");
|
||||
}
|
||||
|
||||
if(!response.isSuccess())
|
||||
{
|
||||
throw new RpcException(response);
|
||||
}
|
||||
|
||||
if(response.getResponse().getResult() instanceof Map<?,?>)
|
||||
{
|
||||
return new ImageCaptcha((Map<String, Object>) response.getResponse().getResult());
|
||||
}
|
||||
|
||||
throw new RpcException("Unexpected result type, expected Map<?,?>");
|
||||
}
|
||||
|
||||
public boolean verificationAnswerImageCaptcha(String answer) throws RpcException
|
||||
{
|
||||
RpcResult response = this.sendRequest(new RpcRequest("verificationAnswerImageCaptcha", Utilities.randomCrc32(), new HashMap<>()
|
||||
{{
|
||||
put("answer", answer);
|
||||
}}));
|
||||
|
||||
if(response == null)
|
||||
{
|
||||
throw new RpcException("Response is null");
|
||||
}
|
||||
|
||||
if(!response.isSuccess())
|
||||
{
|
||||
throw new RpcException(response);
|
||||
}
|
||||
|
||||
return (boolean)response.getResponse().getResult();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,10 @@ import java.util.Hashtable;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Resolver {
|
||||
public static ResolvedServer resolveDomain(String domain) throws ResolutionException {
|
||||
public class Resolver
|
||||
{
|
||||
public static ResolvedServer resolveDomain(String domain) throws ResolutionException
|
||||
{
|
||||
final Pattern fullPattern = Pattern.compile("v=socialbox;sb-rpc=(https?://[^;]+);sb-key=([^;]+)");
|
||||
|
||||
Hashtable<String, String> env = new Hashtable<>();
|
||||
|
@ -18,18 +20,21 @@ public class Resolver {
|
|||
env.put("com.sun.jndi.dns.cache.ttl", "1");
|
||||
env.put("com.sun.jndi.dns.cache.negative.ttl", "0");
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
DirContext dirContext = new InitialDirContext(env);
|
||||
Attributes attributes = dirContext.getAttributes("dns:/" + domain, new String[]{"TXT"});
|
||||
Attribute attributeTXT = attributes.get("TXT");
|
||||
|
||||
if (attributeTXT == null) {
|
||||
if (attributeTXT == null)
|
||||
{
|
||||
throw new ResolutionException("Failed to resolve DNS TXT records for " + domain);
|
||||
}
|
||||
|
||||
StringBuilder fullRecordBuilder = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < attributeTXT.size(); i++) {
|
||||
for (int i = 0; i < attributeTXT.size(); i++)
|
||||
{
|
||||
String value = (String) attributeTXT.get(i);
|
||||
fullRecordBuilder.append(value.replaceAll("^\"|\"$", "").trim());
|
||||
}
|
||||
|
@ -37,23 +42,30 @@ public class Resolver {
|
|||
String fullRecord = fullRecordBuilder.toString();
|
||||
Matcher matcher = fullPattern.matcher(fullRecord);
|
||||
|
||||
if (matcher.find()) {
|
||||
if (matcher.find())
|
||||
{
|
||||
String endpoint = matcher.group(1);
|
||||
String publicKey = matcher.group(2).replaceAll("\\s+", "");
|
||||
|
||||
if (endpoint == null || endpoint.isEmpty()) {
|
||||
if (endpoint == null || endpoint.isEmpty())
|
||||
{
|
||||
throw new ResolutionException("Failed to resolve RPC endpoint for " + domain);
|
||||
}
|
||||
|
||||
if (publicKey == null || publicKey.isEmpty()) {
|
||||
if (publicKey == null || publicKey.isEmpty())
|
||||
{
|
||||
throw new ResolutionException("Failed to resolve public key for " + domain);
|
||||
}
|
||||
|
||||
return new ResolvedServer(endpoint, publicKey);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ResolutionException("Failed to find valid SocialBox record for " + domain);
|
||||
}
|
||||
} catch (NamingException e) {
|
||||
}
|
||||
catch (NamingException e)
|
||||
{
|
||||
throw new ResolutionException("Error resolving domain: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,423 +1,426 @@
|
|||
package net.nosial.socialclient.classes;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.squareup.okhttp.*;
|
||||
import net.nosial.socialclient.abstracts.RpcResult;
|
||||
import net.nosial.socialclient.exceptions.CryptographyException;
|
||||
import net.nosial.socialclient.exceptions.ResolutionException;
|
||||
import net.nosial.socialclient.objects.ResolvedServer;
|
||||
import net.nosial.socialclient.objects.RpcRequest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class RpcClient
|
||||
{
|
||||
private final static ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
private final static MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8");
|
||||
|
||||
private final String domain;
|
||||
private final String endpoint;
|
||||
private final PublicKey serverPublicKey;
|
||||
private final OkHttpClient httpClient;
|
||||
|
||||
private String clientName = "SocialClient Java";
|
||||
private String clientVersion = "1.0.0";
|
||||
|
||||
protected String sessionUuid;
|
||||
protected PrivateKey privateKey;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the RpcClient class using the specified domain.
|
||||
* This constructor resolves the domain to obtain the RPC endpoint and public key.
|
||||
*
|
||||
* @param domain The domain to be resolved for the RPC endpoint and public key.
|
||||
* @throws ResolutionException If the domain cannot be resolved or if required information is missing.
|
||||
* @throws CryptographyException If an error occurs while importing the public key.
|
||||
*/
|
||||
public RpcClient(String domain) throws ResolutionException, CryptographyException
|
||||
package net.nosial.socialclient.classes;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.squareup.okhttp.*;
|
||||
import net.nosial.socialclient.abstracts.RpcResult;
|
||||
import net.nosial.socialclient.exceptions.CryptographyException;
|
||||
import net.nosial.socialclient.exceptions.ResolutionException;
|
||||
import net.nosial.socialclient.objects.ResolvedServer;
|
||||
import net.nosial.socialclient.objects.RpcRequest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class RpcClient
|
||||
{
|
||||
this.domain = domain;
|
||||
this.httpClient = new OkHttpClient();
|
||||
|
||||
// Resolve the domain to get the endpoint and public key
|
||||
ResolvedServer resolvedServer = Resolver.resolveDomain(domain);
|
||||
|
||||
this.endpoint = resolvedServer.getEndpoint();
|
||||
this.serverPublicKey = Cryptography.importPublicKey(resolvedServer.getPublicKey());
|
||||
this.sessionUuid = null;
|
||||
this.privateKey = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an RpcClient instance with the specified endpoint and public key.
|
||||
*
|
||||
* @param endpoint The endpoint to which RPC requests will be sent.
|
||||
* @param serverPublicKey The public key used for cryptographic operations with the RPC server.
|
||||
*/
|
||||
public RpcClient(String endpoint, PublicKey serverPublicKey)
|
||||
{
|
||||
this.domain = null;
|
||||
this.endpoint = endpoint;
|
||||
this.serverPublicKey = serverPublicKey;
|
||||
this.httpClient = new OkHttpClient();
|
||||
this.sessionUuid = null;
|
||||
this.privateKey = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the domain associated with this RpcClient instance.
|
||||
*
|
||||
* @return the domain as a string.
|
||||
*/
|
||||
public String getDomain()
|
||||
{
|
||||
return this.domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the RPC endpoint for the client.
|
||||
*
|
||||
* @return the endpoint as a String.
|
||||
*/
|
||||
public String getEndpoint()
|
||||
{
|
||||
return this.endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public key associated with the RpcClient instance.
|
||||
*
|
||||
* @return the public key as a PublicKey object.
|
||||
*/
|
||||
public PublicKey getServerPublicKey()
|
||||
{
|
||||
return this.serverPublicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the session UUID associated with the RpcClient instance.
|
||||
*
|
||||
* @return the session UUID as a string.
|
||||
*/
|
||||
public String getSessionUuid()
|
||||
{
|
||||
return this.sessionUuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the session UUID and imports the provided private key.
|
||||
*
|
||||
* @param sessionUuid the unique identifier for this session
|
||||
* @param privateKey the private key to be imported
|
||||
* @throws CryptographyException if an error occurs while importing the private key
|
||||
*/
|
||||
protected void setSession(String sessionUuid, String privateKey) throws CryptographyException
|
||||
{
|
||||
this.sessionUuid = sessionUuid;
|
||||
this.privateKey = Cryptography.importPrivateKey(privateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the session details for the RPC client.
|
||||
*
|
||||
* @param sessionUuid the UUID of the session
|
||||
* @param privateKey the private key associated with the session
|
||||
*/
|
||||
protected void setSession(String sessionUuid, PrivateKey privateKey)
|
||||
{
|
||||
this.sessionUuid = sessionUuid;
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the client name associated with this RpcClient instance.
|
||||
*
|
||||
* @return the client name as a string.
|
||||
*/
|
||||
public String getClientName()
|
||||
{
|
||||
return clientName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the client.
|
||||
*
|
||||
* @param clientName The name to be set for the client.
|
||||
* @throws NullPointerException if the provided*/
|
||||
public void setClientName(String clientName)
|
||||
{
|
||||
if(clientName == null)
|
||||
private final static ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
private final static MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8");
|
||||
|
||||
private final String domain;
|
||||
private final String endpoint;
|
||||
private final PublicKey serverPublicKey;
|
||||
private final OkHttpClient httpClient;
|
||||
|
||||
private String clientName = "SocialClient Java";
|
||||
private String clientVersion = "1.0";
|
||||
|
||||
protected String sessionUuid;
|
||||
protected PrivateKey privateKey;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the RpcClient class using the specified domain.
|
||||
* This constructor resolves the domain to obtain the RPC endpoint and public key.
|
||||
*
|
||||
* @param domain The domain to be resolved for the RPC endpoint and public key.
|
||||
* @throws ResolutionException If the domain cannot be resolved or if required information is missing.
|
||||
* @throws CryptographyException If an error occurs while importing the public key.
|
||||
*/
|
||||
public RpcClient(String domain) throws ResolutionException, CryptographyException
|
||||
{
|
||||
throw new NullPointerException("Client name cannot be null");
|
||||
this.domain = domain;
|
||||
this.httpClient = new OkHttpClient();
|
||||
|
||||
// Resolve the domain to get the endpoint and public key
|
||||
ResolvedServer resolvedServer = Resolver.resolveDomain(domain);
|
||||
|
||||
this.endpoint = resolvedServer.getEndpoint();
|
||||
this.serverPublicKey = Cryptography.importPublicKey(resolvedServer.getPublicKey());
|
||||
this.sessionUuid = null;
|
||||
this.privateKey = null;
|
||||
}
|
||||
|
||||
this.clientName = clientName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the client's version.
|
||||
*
|
||||
* @return the client version as a string.
|
||||
*/
|
||||
public String getClientVersion()
|
||||
{
|
||||
return clientVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the client version for the RpcClient instance.
|
||||
*
|
||||
* @param clientVersion The version of the client software to be set.
|
||||
* @throws NullPointerException if the provided clientVersion*/
|
||||
public void setClientVersion(String clientVersion)
|
||||
{
|
||||
if(clientVersion == null)
|
||||
|
||||
/**
|
||||
* Constructs an RpcClient instance with the specified endpoint and public key.
|
||||
*
|
||||
* @param endpoint The endpoint to which RPC requests will be sent.
|
||||
* @param serverPublicKey The public key used for cryptographic operations with the RPC server.
|
||||
*/
|
||||
public RpcClient(String endpoint, PublicKey serverPublicKey)
|
||||
{
|
||||
throw new NullPointerException("Client version cannot be null");
|
||||
this.domain = null;
|
||||
this.endpoint = endpoint;
|
||||
this.serverPublicKey = serverPublicKey;
|
||||
this.httpClient = new OkHttpClient();
|
||||
this.sessionUuid = null;
|
||||
this.privateKey = null;
|
||||
}
|
||||
|
||||
this.clientVersion = clientVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the current session by setting the sessionUuid and privateKey fields to null.
|
||||
* This method effectively logs out the user from the current session.
|
||||
*/
|
||||
public void clearSession()
|
||||
{
|
||||
this.sessionUuid = null;
|
||||
this.privateKey = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an RPC request with the provided JSON data and returns a list of RpcResult objects.
|
||||
*
|
||||
* @param jsonData the JSON-formatted string representing the RPC request data.
|
||||
* @return a list of RpcResult objects representing the response(s) from the RPC server.
|
||||
* @throws RuntimeException if there is an error during the request or response processing.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<RpcResult> sendRequest(String jsonData)
|
||||
{
|
||||
final Request request = new Request.Builder()
|
||||
{{
|
||||
this.url(endpoint);
|
||||
this.post(RequestBody.create(MEDIA_TYPE_JSON, jsonData));
|
||||
this.addHeader("Client-Name", clientName);
|
||||
this.addHeader("Client-Version", clientVersion);
|
||||
|
||||
if(sessionUuid != null)
|
||||
{
|
||||
// We are seeing the session UUID correctly.
|
||||
this.addHeader("Session-UUID", sessionUuid);
|
||||
}
|
||||
|
||||
if(privateKey != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// NOTE: Signature looks okay, it's base64 encoded.
|
||||
System.out.println("Hash: " + Cryptography.sha1(jsonData));
|
||||
System.out.println("Signature: " + Cryptography.signContent(jsonData, privateKey));
|
||||
this.addHeader("Signature", Cryptography.signContent(jsonData, privateKey));
|
||||
}
|
||||
catch(CryptographyException | NoSuchAlgorithmException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}}.build();
|
||||
|
||||
try
|
||||
|
||||
/**
|
||||
* Retrieves the domain associated with this RpcClient instance.
|
||||
*
|
||||
* @return the domain as a string.
|
||||
*/
|
||||
public String getDomain()
|
||||
{
|
||||
final Response response = this.httpClient.newCall(request).execute();
|
||||
final String responseString = response.body().string();
|
||||
|
||||
if (!response.isSuccessful())
|
||||
return this.domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the RPC endpoint for the client.
|
||||
*
|
||||
* @return the endpoint as a String.
|
||||
*/
|
||||
public String getEndpoint()
|
||||
{
|
||||
return this.endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public key associated with the RpcClient instance.
|
||||
*
|
||||
* @return the public key as a PublicKey object.
|
||||
*/
|
||||
public PublicKey getServerPublicKey()
|
||||
{
|
||||
return this.serverPublicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the session UUID associated with the RpcClient instance.
|
||||
*
|
||||
* @return the session UUID as a string.
|
||||
*/
|
||||
public String getSessionUuid()
|
||||
{
|
||||
return this.sessionUuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the session UUID and imports the provided private key.
|
||||
*
|
||||
* @param sessionUuid the unique identifier for this session
|
||||
* @param privateKey the private key to be imported
|
||||
* @throws CryptographyException if an error occurs while importing the private key
|
||||
*/
|
||||
protected void setSession(String sessionUuid, String privateKey) throws CryptographyException
|
||||
{
|
||||
this.sessionUuid = sessionUuid;
|
||||
this.privateKey = Cryptography.importPrivateKey(privateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the session details for the RPC client.
|
||||
*
|
||||
* @param sessionUuid the UUID of the session
|
||||
* @param privateKey the private key associated with the session
|
||||
*/
|
||||
protected void setSession(String sessionUuid, PrivateKey privateKey)
|
||||
{
|
||||
this.sessionUuid = sessionUuid;
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the client name associated with this RpcClient instance.
|
||||
*
|
||||
* @return the client name as a string.
|
||||
*/
|
||||
public String getClientName()
|
||||
{
|
||||
return clientName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the client.
|
||||
*
|
||||
* @param clientName The name to be set for the client.
|
||||
* @throws NullPointerException if the provided*/
|
||||
public void setClientName(String clientName)
|
||||
{
|
||||
if(clientName == null)
|
||||
{
|
||||
if(!responseString.isEmpty())
|
||||
throw new NullPointerException("Client name cannot be null");
|
||||
}
|
||||
|
||||
this.clientName = clientName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the client's version.
|
||||
*
|
||||
* @return the client version as a string.
|
||||
*/
|
||||
public String getClientVersion()
|
||||
{
|
||||
return clientVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the client version for the RpcClient instance.
|
||||
*
|
||||
* @param clientVersion The version of the client software to be set.
|
||||
* @throws NullPointerException if the provided clientVersion*/
|
||||
public void setClientVersion(String clientVersion)
|
||||
{
|
||||
if(clientVersion == null)
|
||||
{
|
||||
throw new NullPointerException("Client version cannot be null");
|
||||
}
|
||||
|
||||
this.clientVersion = clientVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the current session by setting the sessionUuid and privateKey fields to null.
|
||||
* This method effectively logs out the user from the current session.
|
||||
*/
|
||||
public void clearSession()
|
||||
{
|
||||
this.sessionUuid = null;
|
||||
this.privateKey = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an RPC request with the provided JSON data and returns a list of RpcResult objects.
|
||||
*
|
||||
* @param jsonData the JSON-formatted string representing the RPC request data.
|
||||
* @return a list of RpcResult objects representing the response(s) from the RPC server.
|
||||
* @throws RuntimeException if there is an error during the request or response processing.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<RpcResult> sendRequest(String jsonData)
|
||||
{
|
||||
final Request request = new Request.Builder()
|
||||
{{
|
||||
this.url(endpoint);
|
||||
this.post(RequestBody.create(MEDIA_TYPE_JSON, jsonData));
|
||||
this.addHeader("Client-Name", clientName);
|
||||
this.addHeader("Client-Version", clientVersion);
|
||||
|
||||
if(sessionUuid != null)
|
||||
{
|
||||
// We are seeing the session UUID correctly.
|
||||
this.addHeader("Session-UUID", sessionUuid);
|
||||
}
|
||||
|
||||
if(privateKey != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// NOTE: Signature looks okay, it's base64 encoded.
|
||||
this.addHeader("Signature", Cryptography.signContent(jsonData, privateKey));
|
||||
}
|
||||
catch(CryptographyException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}}.build();
|
||||
|
||||
try
|
||||
{
|
||||
final Response response = this.httpClient.newCall(request).execute();
|
||||
final String responseString = response.body().string();
|
||||
|
||||
if (!response.isSuccessful())
|
||||
{
|
||||
throw new RuntimeException(responseString);
|
||||
if(!responseString.isEmpty())
|
||||
{
|
||||
throw new RuntimeException(responseString);
|
||||
}
|
||||
|
||||
throw new RuntimeException("Failed to send request: " + response.code());
|
||||
}
|
||||
|
||||
throw new RuntimeException("Failed to send request: " + response.code());
|
||||
}
|
||||
|
||||
if(response.code() == 204)
|
||||
{
|
||||
// The response is empty
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
Object decoded = decode(responseString);
|
||||
|
||||
// Singular object response
|
||||
if(decoded instanceof List<?>)
|
||||
{
|
||||
List<Map<String, Object>> responseList = (List<Map<String, Object>>) decoded;
|
||||
List<RpcResult> results = new ArrayList<>(responseList.size());
|
||||
for(Map<String, Object> responseMap : responseList)
|
||||
|
||||
if(response.code() == 204)
|
||||
{
|
||||
results.add(RpcResult.fromMap(responseMap));
|
||||
// The response is empty
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
if(decoded instanceof Map<?, ?>)
|
||||
{
|
||||
|
||||
if(responseString.isEmpty())
|
||||
{
|
||||
throw new RuntimeException("The request was successful but the server did not indicate a empty response");
|
||||
}
|
||||
|
||||
Object decoded = decode(responseString);
|
||||
|
||||
// Singular object response
|
||||
List<RpcResult> results = new ArrayList<>(1);
|
||||
results.add(RpcResult.fromMap((Map<String, Object>) decoded));
|
||||
return results;
|
||||
if(decoded instanceof List<?>)
|
||||
{
|
||||
List<Map<String, Object>> responseList = (List<Map<String, Object>>) decoded;
|
||||
List<RpcResult> results = new ArrayList<>(responseList.size());
|
||||
for(Map<String, Object> responseMap : responseList)
|
||||
{
|
||||
results.add(RpcResult.fromMap(responseMap));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
if(decoded instanceof Map<?, ?>)
|
||||
{
|
||||
// Singular object response
|
||||
List<RpcResult> results = new ArrayList<>(1);
|
||||
results.add(RpcResult.fromMap((Map<String, Object>) decoded));
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
throw new RuntimeException("Failed to decode response");
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
|
||||
throw new RuntimeException("Failed to decode response");
|
||||
}
|
||||
catch (IOException e)
|
||||
|
||||
/**
|
||||
* Sends an RPC request to the configured endpoint and returns the first result.
|
||||
*
|
||||
* @param request the RPC request to be sent
|
||||
* @return the first RPC result received from the response
|
||||
*/
|
||||
public RpcResult sendRequest(RpcRequest request)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
List<RpcResult> results = sendRequest(encode(request.toMap()));
|
||||
|
||||
if(results.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return results.getFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a list of RPC requests to the server and returns their results as a list of RpcResult objects.
|
||||
*
|
||||
* @param requests the list of RPC requests to be sent
|
||||
* @return a list of RpcResult objects containing the responses from the server
|
||||
*/
|
||||
public List<RpcResult> sendRequests(List<RpcRequest> requests)
|
||||
{
|
||||
return sendRequest(encode(requests));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a JSON string into a corresponding Java object. If the JSON string
|
||||
* represents an object, it decodes it into a Map. If the JSON string represents
|
||||
* an array, it decodes it into a List.
|
||||
*
|
||||
* @param json the JSON string to be decoded
|
||||
* @return a decoded Java object which can be a Map or a List depending on the JSON structure
|
||||
* @throws RuntimeException if the JSON string is neither an object nor an array, or if decoding fails
|
||||
*/
|
||||
private static Object decode(String json)
|
||||
{
|
||||
try
|
||||
{
|
||||
JsonNode jsonNode = OBJECT_MAPPER.readTree(json);
|
||||
if (jsonNode.isObject())
|
||||
{
|
||||
return decodeJson(OBJECT_MAPPER.readValue(json, new TypeReference<>() {}));
|
||||
}
|
||||
else if (jsonNode.isArray())
|
||||
{
|
||||
return decodeList(OBJECT_MAPPER.readValue(json, new TypeReference<>() {}));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("JSON is neither an object nor an array");
|
||||
}
|
||||
}
|
||||
catch (JsonProcessingException e)
|
||||
{
|
||||
throw new RuntimeException("Failed to decode input", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively decodes a JSON structure represented as a Map. If the value
|
||||
* of an entry is another Map, it recursively decodes that Map. If the value
|
||||
* is a List, it passes the List to the decodeList method.
|
||||
*
|
||||
* @param map the JSON structure to be decoded represented as a Map
|
||||
* @return the decoded JSON structure as a Map
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Map<String, Object> decodeJson(Map<String, Object> map)
|
||||
{
|
||||
for (Map.Entry<String, Object> entry : map.entrySet())
|
||||
{
|
||||
if (entry.getValue() instanceof Map)
|
||||
{
|
||||
entry.setValue(decodeJson((Map<String, Object>) entry.getValue()));
|
||||
}
|
||||
else if (entry.getValue() instanceof List)
|
||||
{
|
||||
entry.setValue(decodeList((List<Object>) entry.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively decodes a list of objects, transforming any nested maps or lists within it.
|
||||
*
|
||||
* @param list the list of objects to be decoded
|
||||
* @return the decoded list of objects, with all nested maps and lists transformed
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static List<Object> decodeList(List<Object> list)
|
||||
{
|
||||
for (int i = 0; i < list.size(); i++)
|
||||
{
|
||||
final Object item = list.get(i);
|
||||
if (item instanceof Map)
|
||||
{
|
||||
list.set(i, decodeJson((Map<String, Object>) item));
|
||||
}
|
||||
else if (item instanceof List)
|
||||
{
|
||||
list.set(i, decodeList((List<Object>) item));
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given input object to its JSON string representation.
|
||||
*
|
||||
* @param input the object to encode
|
||||
* @return the JSON string representation of the input object
|
||||
*/
|
||||
private static String encode(Object input)
|
||||
{
|
||||
try
|
||||
{
|
||||
return OBJECT_MAPPER.writeValueAsString(input);
|
||||
}
|
||||
catch(JsonProcessingException e)
|
||||
{
|
||||
throw new RuntimeException("Failed to encode input to JSON Data", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an RPC request to the configured endpoint and returns the first result.
|
||||
*
|
||||
* @param request the RPC request to be sent
|
||||
* @return the first RPC result received from the response
|
||||
*/
|
||||
public RpcResult sendRequest(RpcRequest request)
|
||||
{
|
||||
List<RpcResult> results = sendRequest(encode(request.toMap()));
|
||||
|
||||
if(results.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return results.getFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a list of RPC requests to the server and returns their results as a list of RpcResult objects.
|
||||
*
|
||||
* @param requests the list of RPC requests to be sent
|
||||
* @return a list of RpcResult objects containing the responses from the server
|
||||
*/
|
||||
public List<RpcResult> sendRequests(List<RpcRequest> requests)
|
||||
{
|
||||
return sendRequest(encode(requests));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a JSON string into a corresponding Java object. If the JSON string
|
||||
* represents an object, it decodes it into a Map. If the JSON string represents
|
||||
* an array, it decodes it into a List.
|
||||
*
|
||||
* @param json the JSON string to be decoded
|
||||
* @return a decoded Java object which can be a Map or a List depending on the JSON structure
|
||||
* @throws RuntimeException if the JSON string is neither an object nor an array, or if decoding fails
|
||||
*/
|
||||
private static Object decode(String json)
|
||||
{
|
||||
try
|
||||
{
|
||||
JsonNode jsonNode = OBJECT_MAPPER.readTree(json);
|
||||
if (jsonNode.isObject())
|
||||
{
|
||||
return decodeJson(OBJECT_MAPPER.readValue(json, new TypeReference<>() {}));
|
||||
}
|
||||
else if (jsonNode.isArray())
|
||||
{
|
||||
return decodeList(OBJECT_MAPPER.readValue(json, new TypeReference<>() {}));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("JSON is neither an object nor an array");
|
||||
}
|
||||
}
|
||||
catch (JsonProcessingException e)
|
||||
{
|
||||
throw new RuntimeException("Failed to decode input", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively decodes a JSON structure represented as a Map. If the value
|
||||
* of an entry is another Map, it recursively decodes that Map. If the value
|
||||
* is a List, it passes the List to the decodeList method.
|
||||
*
|
||||
* @param map the JSON structure to be decoded represented as a Map
|
||||
* @return the decoded JSON structure as a Map
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Map<String, Object> decodeJson(Map<String, Object> map)
|
||||
{
|
||||
for (Map.Entry<String, Object> entry : map.entrySet())
|
||||
{
|
||||
if (entry.getValue() instanceof Map)
|
||||
{
|
||||
entry.setValue(decodeJson((Map<String, Object>) entry.getValue()));
|
||||
}
|
||||
else if (entry.getValue() instanceof List)
|
||||
{
|
||||
entry.setValue(decodeList((List<Object>) entry.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively decodes a list of objects, transforming any nested maps or lists within it.
|
||||
*
|
||||
* @param list the list of objects to be decoded
|
||||
* @return the decoded list of objects, with all nested maps and lists transformed
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static List<Object> decodeList(List<Object> list)
|
||||
{
|
||||
for (int i = 0; i < list.size(); i++)
|
||||
{
|
||||
final Object item = list.get(i);
|
||||
if (item instanceof Map)
|
||||
{
|
||||
list.set(i, decodeJson((Map<String, Object>) item));
|
||||
}
|
||||
else if (item instanceof List)
|
||||
{
|
||||
list.set(i, decodeList((List<Object>) item));
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the given input object to its JSON string representation.
|
||||
*
|
||||
* @param input the object to encode
|
||||
* @return the JSON string representation of the input object
|
||||
*/
|
||||
private static String encode(Object input)
|
||||
{
|
||||
try
|
||||
{
|
||||
return OBJECT_MAPPER.writeValueAsString(input);
|
||||
}
|
||||
catch(JsonProcessingException e)
|
||||
{
|
||||
throw new RuntimeException("Failed to encode input to JSON Data", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,15 @@ public enum StandardErrorCodes
|
|||
SERVER_UNAVAILABLE(-2001),
|
||||
|
||||
INVALID_PUBLIC_KEY(-3000),
|
||||
SESSION_NOT_FOUND(-3001),
|
||||
UNSUPPORTED_AUTHENTICATION_TYPE(-3002);
|
||||
UNSUPPORTED_AUTHENTICATION_TYPE(-3001),
|
||||
ALREADY_AUTHENTICATED(-3002),
|
||||
AUTHENTICATION_REQUIRED(-3003),
|
||||
SESSION_NOT_FOUND(-3004),
|
||||
SESSION_REQUIRED(-3005),
|
||||
|
||||
PEER_NOT_FOUND(-4000),
|
||||
INVALID_USERNAME(-4001),
|
||||
USERNAME_ALREADY_EXISTS(-4002);
|
||||
|
||||
private final int code;
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package net.nosial.socialclient.enums.flags;
|
||||
|
||||
public enum PeerFlags
|
||||
{
|
||||
// Administrative Flags
|
||||
ADMIN(true, "ADMIN"),
|
||||
MODERATOR(true, "MODERATOR"),
|
||||
|
||||
// General Flags
|
||||
VERIFIED(true, "VERIFIED"),
|
||||
|
||||
// Verification Flags
|
||||
VER_SET_PASSWORD(false, "VER_SET_PASSWORD"),
|
||||
VER_SET_OTP(false, "VER_SET_OTP"),
|
||||
VER_SET_DISPLAY_NAME(false, "VER_SET_DISPLAY_NAME"),
|
||||
VER_EMAIL(false, "VER_EMAIL"),
|
||||
VER_SMS(false, "VER_SMS"),
|
||||
VER_PHONE_CALL(false, "VER_PHONE_CALL"),
|
||||
VER_SOLVE_IMAGE_CAPTCHA(false, "VER_SOLVE_IMAGE_CAPTCHA");
|
||||
|
||||
private final boolean isPublic;
|
||||
private final String flag;
|
||||
|
||||
PeerFlags(boolean isPublic, String flag)
|
||||
{
|
||||
this.isPublic = isPublic;
|
||||
this.flag = flag;
|
||||
}
|
||||
|
||||
public String getFlag()
|
||||
{
|
||||
return this.flag;
|
||||
}
|
||||
|
||||
public boolean isPublic()
|
||||
{
|
||||
return this.isPublic;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package net.nosial.socialclient.objects.standard;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
|
||||
public class ImageCaptcha
|
||||
{
|
||||
private final int expires;
|
||||
private final String image;
|
||||
|
||||
public ImageCaptcha(Map<String, Object> data)
|
||||
{
|
||||
this.expires = (int) data.get("expires");
|
||||
this.image = (String) data.get("image");
|
||||
}
|
||||
|
||||
public int getExpires()
|
||||
{
|
||||
return expires;
|
||||
}
|
||||
|
||||
public String getImage()
|
||||
{
|
||||
return image;
|
||||
}
|
||||
|
||||
public BufferedImage getImageBuffer() throws IOException
|
||||
{
|
||||
String base64Image = this.image;
|
||||
if(this.image.contains(","))
|
||||
{
|
||||
base64Image = this.image.split(",")[1];
|
||||
}
|
||||
|
||||
byte[] imageBytes = Base64.getDecoder().decode(base64Image);
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(imageBytes);
|
||||
BufferedImage image = javax.imageio.ImageIO.read(bis);
|
||||
bis.close();
|
||||
|
||||
return image;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
package net.nosial.socialclient.objects.standard;
|
||||
|
||||
import net.nosial.socialclient.enums.flags.PeerFlags;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class SelfUser
|
||||
{
|
||||
private final String uuid;
|
||||
private final boolean enabled;
|
||||
private final String address;
|
||||
private final String username;
|
||||
private final String displayName;
|
||||
private final List<PeerFlags> flags;
|
||||
private final int created;
|
||||
|
||||
/**
|
||||
* Constructs a SelfUser instance by populating fields from a provided data map.
|
||||
*
|
||||
* @param data a map containing user details such as uuid, username, display name, flags,
|
||||
* enabled status, and creation time.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public SelfUser(Map<String, Object> data)
|
||||
{
|
||||
this.uuid = (String) data.get("uuid");
|
||||
this.enabled = (boolean) data.get("enabled");
|
||||
this.username = (String) data.get("username");
|
||||
this.address = (String) data.get("address");
|
||||
this.displayName = (String) data.get("display_name");
|
||||
this.flags = ((List<String>) data.get("flags")).stream().map(PeerFlags::valueOf).collect(Collectors.toList());
|
||||
this.created = (int) data.get("created");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the universally unique identifier (UUID) associated with the user.
|
||||
*
|
||||
* @return the UUID as a String
|
||||
*/
|
||||
public String getUuid()
|
||||
{
|
||||
return uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user account is enabled.
|
||||
*
|
||||
* @return true if the user account is enabled; false otherwise.
|
||||
*/
|
||||
public boolean isEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the username associated with this SelfUser instance.
|
||||
*
|
||||
* @return the username of the user
|
||||
*/
|
||||
public String getUsername()
|
||||
{
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the address associated with this SelfUser instance.
|
||||
*
|
||||
* @return the address of the user
|
||||
*/
|
||||
public String getAddress()
|
||||
{
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the display name of the user.
|
||||
*
|
||||
* @return the display name of the user
|
||||
*/
|
||||
public String getDisplayName()
|
||||
{
|
||||
return displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the list of flags associated with the user.
|
||||
*
|
||||
* @return a list of PeerFlags indicating various user permissions and statuses.
|
||||
*/
|
||||
public List<PeerFlags> getFlags()
|
||||
{
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the creation timestamp of this user.
|
||||
*
|
||||
* @return the creation timestamp as an integer
|
||||
*/
|
||||
public int getCreated()
|
||||
{
|
||||
return created;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package net.nosial.socialclient;
|
||||
package net.nosial.socialclient.methods;
|
||||
|
||||
import net.nosial.socialclient.Client;
|
||||
import net.nosial.socialclient.classes.Cryptography;
|
||||
import net.nosial.socialclient.exceptions.CryptographyException;
|
||||
import net.nosial.socialclient.exceptions.ResolutionException;
|
||||
|
@ -10,11 +11,10 @@ import java.security.KeyPair;
|
|||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class SessionTest
|
||||
public class CreateSessionTest
|
||||
{
|
||||
|
||||
@Test
|
||||
void createSessionTest()
|
||||
void testSessionCreation()
|
||||
{
|
||||
Client socialClient;
|
||||
KeyPair keyPair;
|
||||
|
@ -23,18 +23,9 @@ class SessionTest
|
|||
try
|
||||
{
|
||||
socialClient = new Client("n64.cc");
|
||||
}
|
||||
catch (ResolutionException | CryptographyException e)
|
||||
{
|
||||
fail(e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
keyPair = Cryptography.generateKeyPair();
|
||||
}
|
||||
catch (CryptographyException e)
|
||||
catch (ResolutionException | CryptographyException e)
|
||||
{
|
||||
fail(e.getMessage(), e);
|
||||
return;
|
||||
|
@ -86,4 +77,4 @@ class SessionTest
|
|||
fail(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
127
src/test/java/net/nosial/socialclient/methods/RegisterTest.java
Normal file
127
src/test/java/net/nosial/socialclient/methods/RegisterTest.java
Normal file
|
@ -0,0 +1,127 @@
|
|||
package net.nosial.socialclient.methods;
|
||||
|
||||
import net.nosial.socialclient.Client;
|
||||
import net.nosial.socialclient.classes.Cryptography;
|
||||
import net.nosial.socialclient.exceptions.CryptographyException;
|
||||
import net.nosial.socialclient.exceptions.ResolutionException;
|
||||
import net.nosial.socialclient.exceptions.RpcException;
|
||||
import net.nosial.socialclient.objects.standard.ImageCaptcha;
|
||||
import net.nosial.socialclient.objects.standard.SelfUser;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.security.KeyPair;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class RegisterTest
|
||||
{
|
||||
@Test
|
||||
public void registerTest()
|
||||
{
|
||||
// Step 1. Connect and establish a session to the server
|
||||
final Client socialClient;
|
||||
final KeyPair keyPair;
|
||||
final String sessionUuid;
|
||||
|
||||
try
|
||||
{
|
||||
socialClient = new Client("n64.cc");
|
||||
keyPair = Cryptography.generateKeyPair();
|
||||
sessionUuid = socialClient.createAndSetSession(keyPair);
|
||||
|
||||
}
|
||||
catch (ResolutionException | CryptographyException | RpcException e)
|
||||
{
|
||||
fail(e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("Session UUID: " + sessionUuid);
|
||||
assertNotNull(sessionUuid);
|
||||
|
||||
final SelfUser selfUser;
|
||||
Random random = new Random();
|
||||
String username = "user" + random.nextInt(10000);
|
||||
|
||||
// Step 2. Register the username and getSelf
|
||||
try
|
||||
{
|
||||
assertTrue(socialClient.register(username));
|
||||
selfUser = socialClient.getMe();
|
||||
}
|
||||
catch (RpcException e)
|
||||
{
|
||||
fail(e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
|
||||
assertNotNull(selfUser);
|
||||
|
||||
// Step 3. Get the captcha
|
||||
ImageCaptcha captcha;
|
||||
|
||||
try
|
||||
{
|
||||
captcha = socialClient.verificationGetImageCaptcha();
|
||||
}
|
||||
catch(RpcException e)
|
||||
{
|
||||
fail(e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
try
|
||||
{
|
||||
ImageFrame frame = new ImageFrame(captcha.getImageBuffer());
|
||||
frame.setVisible(true);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
assertNotNull(captcha);
|
||||
|
||||
// Step 4. Verify the captcha, get input from the user
|
||||
String captchaInput = JOptionPane.showInputDialog("Enter the captcha: ");
|
||||
assertNotNull(captchaInput);
|
||||
|
||||
// Step 5. Verify the captcha
|
||||
try
|
||||
{
|
||||
assertTrue(socialClient.verificationAnswerImageCaptcha(captchaInput));
|
||||
}
|
||||
catch(RpcException e)
|
||||
{
|
||||
fail(e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ImageFrame extends JFrame {
|
||||
public ImageFrame(BufferedImage image) {
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setResizable(false);
|
||||
|
||||
JPanel panel = new JPanel() {
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
g.drawImage(image, 0, 0, null);
|
||||
}
|
||||
};
|
||||
|
||||
panel.setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
|
||||
add(panel);
|
||||
pack();
|
||||
setLocationRelativeTo(null);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue