mirror of
https://github.com/signalapp/Signal-Server.git
synced 2025-12-15 02:00:48 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9bd1c679e | ||
|
|
437eb8de37 | ||
|
|
f14c181840 | ||
|
|
d46c9fb157 | ||
|
|
6913e4dfd2 | ||
|
|
aea3f299a0 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,3 +7,5 @@ run.sh
|
|||||||
local.yml
|
local.yml
|
||||||
config/production.yml
|
config/production.yml
|
||||||
config/federated.yml
|
config/federated.yml
|
||||||
|
config/staging.yml
|
||||||
|
.opsmanage
|
||||||
|
|||||||
2
pom.xml
2
pom.xml
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
<groupId>org.whispersystems.textsecure</groupId>
|
<groupId>org.whispersystems.textsecure</groupId>
|
||||||
<artifactId>TextSecureServer</artifactId>
|
<artifactId>TextSecureServer</artifactId>
|
||||||
<version>0.7</version>
|
<version>0.10</version>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
import com.yammer.dropwizard.config.Configuration;
|
import com.yammer.dropwizard.config.Configuration;
|
||||||
import com.yammer.dropwizard.db.DatabaseConfiguration;
|
import com.yammer.dropwizard.db.DatabaseConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.ApnConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.ApnConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.DataDogConfiguration;
|
|
||||||
import org.whispersystems.textsecuregcm.configuration.FederationConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.FederationConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.GcmConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.GcmConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.GraphiteConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.GraphiteConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.MemcacheConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.MemcacheConfiguration;
|
||||||
|
import org.whispersystems.textsecuregcm.configuration.MetricsConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.NexmoConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.NexmoConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.RateLimitsConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.RateLimitsConfiguration;
|
||||||
import org.whispersystems.textsecuregcm.configuration.RedisConfiguration;
|
import org.whispersystems.textsecuregcm.configuration.RedisConfiguration;
|
||||||
@@ -87,7 +87,7 @@ public class WhisperServerConfiguration extends Configuration {
|
|||||||
|
|
||||||
@Valid
|
@Valid
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private DataDogConfiguration datadog = new DataDogConfiguration();
|
private MetricsConfiguration metrics = new MetricsConfiguration();
|
||||||
|
|
||||||
@Valid
|
@Valid
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
@@ -141,7 +141,7 @@ public class WhisperServerConfiguration extends Configuration {
|
|||||||
return graphite;
|
return graphite;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataDogConfiguration getDataDogConfiguration() {
|
public MetricsConfiguration getMetricsConfiguration() {
|
||||||
return datadog;
|
return metrics;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,9 +24,7 @@ import com.yammer.dropwizard.config.HttpConfiguration;
|
|||||||
import com.yammer.dropwizard.db.DatabaseConfiguration;
|
import com.yammer.dropwizard.db.DatabaseConfiguration;
|
||||||
import com.yammer.dropwizard.jdbi.DBIFactory;
|
import com.yammer.dropwizard.jdbi.DBIFactory;
|
||||||
import com.yammer.dropwizard.migrations.MigrationsBundle;
|
import com.yammer.dropwizard.migrations.MigrationsBundle;
|
||||||
import com.yammer.metrics.core.Clock;
|
import com.yammer.metrics.Metrics;
|
||||||
import com.yammer.metrics.core.MetricPredicate;
|
|
||||||
import com.yammer.metrics.reporting.DatadogReporter;
|
|
||||||
import com.yammer.metrics.reporting.GraphiteReporter;
|
import com.yammer.metrics.reporting.GraphiteReporter;
|
||||||
import net.spy.memcached.MemcachedClient;
|
import net.spy.memcached.MemcachedClient;
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
@@ -48,6 +46,11 @@ import org.whispersystems.textsecuregcm.federation.FederatedPeer;
|
|||||||
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||||
import org.whispersystems.textsecuregcm.mappers.IOExceptionMapper;
|
import org.whispersystems.textsecuregcm.mappers.IOExceptionMapper;
|
||||||
import org.whispersystems.textsecuregcm.mappers.RateLimitExceededExceptionMapper;
|
import org.whispersystems.textsecuregcm.mappers.RateLimitExceededExceptionMapper;
|
||||||
|
import org.whispersystems.textsecuregcm.metrics.CpuUsageGauge;
|
||||||
|
import org.whispersystems.textsecuregcm.metrics.FreeMemoryGauge;
|
||||||
|
import org.whispersystems.textsecuregcm.metrics.JsonMetricsReporter;
|
||||||
|
import org.whispersystems.textsecuregcm.metrics.NetworkReceivedGauge;
|
||||||
|
import org.whispersystems.textsecuregcm.metrics.NetworkSentGauge;
|
||||||
import org.whispersystems.textsecuregcm.providers.MemcacheHealthCheck;
|
import org.whispersystems.textsecuregcm.providers.MemcacheHealthCheck;
|
||||||
import org.whispersystems.textsecuregcm.providers.MemcachedClientFactory;
|
import org.whispersystems.textsecuregcm.providers.MemcachedClientFactory;
|
||||||
import org.whispersystems.textsecuregcm.providers.RedisClientFactory;
|
import org.whispersystems.textsecuregcm.providers.RedisClientFactory;
|
||||||
@@ -162,17 +165,22 @@ public class WhisperServerService extends Service<WhisperServerConfiguration> {
|
|||||||
environment.addProvider(new IOExceptionMapper());
|
environment.addProvider(new IOExceptionMapper());
|
||||||
environment.addProvider(new RateLimitExceededExceptionMapper());
|
environment.addProvider(new RateLimitExceededExceptionMapper());
|
||||||
|
|
||||||
|
Metrics.newGauge(CpuUsageGauge.class, "cpu", new CpuUsageGauge());
|
||||||
|
Metrics.newGauge(FreeMemoryGauge.class, "free_memory", new FreeMemoryGauge());
|
||||||
|
Metrics.newGauge(NetworkSentGauge.class, "bytes_sent", new NetworkSentGauge());
|
||||||
|
Metrics.newGauge(NetworkReceivedGauge.class, "bytes_received", new NetworkReceivedGauge());
|
||||||
|
|
||||||
if (config.getGraphiteConfiguration().isEnabled()) {
|
if (config.getGraphiteConfiguration().isEnabled()) {
|
||||||
GraphiteReporter.enable(15, TimeUnit.SECONDS,
|
GraphiteReporter.enable(15, TimeUnit.SECONDS,
|
||||||
config.getGraphiteConfiguration().getHost(),
|
config.getGraphiteConfiguration().getHost(),
|
||||||
config.getGraphiteConfiguration().getPort());
|
config.getGraphiteConfiguration().getPort());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.getDataDogConfiguration().isEnabled()) {
|
if (config.getMetricsConfiguration().isEnabled()) {
|
||||||
new DatadogReporter.Builder().withApiKey(config.getDataDogConfiguration().getApiKey())
|
new JsonMetricsReporter("textsecure", Metrics.defaultRegistry(),
|
||||||
.withVmMetricsEnabled(true)
|
config.getMetricsConfiguration().getToken(),
|
||||||
.build()
|
config.getMetricsConfiguration().getHost())
|
||||||
.start(15, TimeUnit.SECONDS);
|
.start(60, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package org.whispersystems.textsecuregcm.configuration;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
public class MetricsConfiguration {
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private boolean enabled = false;
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled && token != null && host != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,9 @@ package org.whispersystems.textsecuregcm.controllers;
|
|||||||
|
|
||||||
import com.google.common.base.Optional;
|
import com.google.common.base.Optional;
|
||||||
import com.yammer.dropwizard.auth.Auth;
|
import com.yammer.dropwizard.auth.Auth;
|
||||||
|
import com.yammer.metrics.Metrics;
|
||||||
import com.yammer.metrics.annotation.Timed;
|
import com.yammer.metrics.annotation.Timed;
|
||||||
|
import com.yammer.metrics.core.Histogram;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.whispersystems.textsecuregcm.entities.ClientContact;
|
import org.whispersystems.textsecuregcm.entities.ClientContact;
|
||||||
@@ -46,7 +48,8 @@ import java.util.List;
|
|||||||
@Path("/v1/directory")
|
@Path("/v1/directory")
|
||||||
public class DirectoryController {
|
public class DirectoryController {
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(DirectoryController.class);
|
private final Logger logger = LoggerFactory.getLogger(DirectoryController.class);
|
||||||
|
private final Histogram contactsHistogram = Metrics.newHistogram(DirectoryController.class, "contacts");
|
||||||
|
|
||||||
private final RateLimiters rateLimiters;
|
private final RateLimiters rateLimiters;
|
||||||
private final DirectoryManager directory;
|
private final DirectoryManager directory;
|
||||||
@@ -56,7 +59,7 @@ public class DirectoryController {
|
|||||||
this.rateLimiters = rateLimiters;
|
this.rateLimiters = rateLimiters;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Timed()
|
@Timed
|
||||||
@GET
|
@GET
|
||||||
@Path("/{token}")
|
@Path("/{token}")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@@ -77,7 +80,7 @@ public class DirectoryController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Timed()
|
@Timed
|
||||||
@PUT
|
@PUT
|
||||||
@Path("/tokens")
|
@Path("/tokens")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@@ -86,6 +89,7 @@ public class DirectoryController {
|
|||||||
throws RateLimitExceededException
|
throws RateLimitExceededException
|
||||||
{
|
{
|
||||||
rateLimiters.getContactsLimiter().validate(account.getNumber(), contacts.getContacts().size());
|
rateLimiters.getContactsLimiter().validate(account.getNumber(), contacts.getContacts().size());
|
||||||
|
contactsHistogram.update(contacts.getContacts().size());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<byte[]> tokens = new LinkedList<>();
|
List<byte[]> tokens = new LinkedList<>();
|
||||||
|
|||||||
@@ -70,7 +70,14 @@ public class KeysController {
|
|||||||
@PUT
|
@PUT
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
public void setKeys(@Auth Account account, @Valid PreKeyList preKeys) {
|
public void setKeys(@Auth Account account, @Valid PreKeyList preKeys) {
|
||||||
Device device = account.getAuthenticatedDevice().get();
|
Device device = account.getAuthenticatedDevice().get();
|
||||||
|
String identityKey = preKeys.getLastResortKey().getIdentityKey();
|
||||||
|
|
||||||
|
if (!identityKey.equals(account.getIdentityKey())) {
|
||||||
|
account.setIdentityKey(identityKey);
|
||||||
|
accounts.update(account);
|
||||||
|
}
|
||||||
|
|
||||||
keys.store(account.getNumber(), device.getId(), preKeys.getKeys(), preKeys.getLastResortKey());
|
keys.store(account.getNumber(), device.getId(), preKeys.getKeys(), preKeys.getLastResortKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,4 +30,11 @@ public class ClientContactTokens {
|
|||||||
public List<String> getContacts() {
|
public List<String> getContacts() {
|
||||||
return contacts;
|
return contacts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ClientContactTokens() {}
|
||||||
|
|
||||||
|
public ClientContactTokens(List<String> contacts) {
|
||||||
|
this.contacts = contacts;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package org.whispersystems.textsecuregcm.entities;
|
package org.whispersystems.textsecuregcm.entities;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import org.hibernate.validator.constraints.NotEmpty;
|
import org.hibernate.validator.constraints.NotEmpty;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
@@ -27,6 +28,7 @@ public class PreKeyList {
|
|||||||
|
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@Valid
|
||||||
private PreKey lastResortKey;
|
private PreKey lastResortKey;
|
||||||
|
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
@@ -38,7 +40,17 @@ public class PreKeyList {
|
|||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public void setKeys(List<PreKey> keys) {
|
||||||
|
this.keys = keys;
|
||||||
|
}
|
||||||
|
|
||||||
public PreKey getLastResortKey() {
|
public PreKey getLastResortKey() {
|
||||||
return lastResortKey;
|
return lastResortKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public void setLastResortKey(PreKey lastResortKey) {
|
||||||
|
this.lastResortKey = lastResortKey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.whispersystems.textsecuregcm.metrics;
|
||||||
|
|
||||||
|
import com.sun.management.OperatingSystemMXBean;
|
||||||
|
import com.yammer.metrics.core.Gauge;
|
||||||
|
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
|
|
||||||
|
public class CpuUsageGauge extends Gauge<Integer> {
|
||||||
|
@Override
|
||||||
|
public Integer value() {
|
||||||
|
OperatingSystemMXBean mbean = (com.sun.management.OperatingSystemMXBean)
|
||||||
|
ManagementFactory.getOperatingSystemMXBean();
|
||||||
|
|
||||||
|
return (int) Math.ceil(mbean.getSystemCpuLoad() * 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package org.whispersystems.textsecuregcm.metrics;
|
||||||
|
|
||||||
|
import com.sun.management.OperatingSystemMXBean;
|
||||||
|
import com.yammer.metrics.core.Gauge;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
|
|
||||||
|
public class FreeMemoryGauge extends Gauge<Long> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long value() {
|
||||||
|
OperatingSystemMXBean mbean = (com.sun.management.OperatingSystemMXBean)
|
||||||
|
ManagementFactory.getOperatingSystemMXBean();
|
||||||
|
|
||||||
|
return mbean.getFreePhysicalMemorySize();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,324 @@
|
|||||||
|
package org.whispersystems.textsecuregcm.metrics;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonEncoding;
|
||||||
|
import com.fasterxml.jackson.core.JsonFactory;
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.yammer.metrics.core.Clock;
|
||||||
|
import com.yammer.metrics.core.Counter;
|
||||||
|
import com.yammer.metrics.core.Gauge;
|
||||||
|
import com.yammer.metrics.core.Histogram;
|
||||||
|
import com.yammer.metrics.core.Metered;
|
||||||
|
import com.yammer.metrics.core.Metric;
|
||||||
|
import com.yammer.metrics.core.MetricName;
|
||||||
|
import com.yammer.metrics.core.MetricProcessor;
|
||||||
|
import com.yammer.metrics.core.MetricsRegistry;
|
||||||
|
import com.yammer.metrics.core.Sampling;
|
||||||
|
import com.yammer.metrics.core.Summarizable;
|
||||||
|
import com.yammer.metrics.core.Timer;
|
||||||
|
import com.yammer.metrics.core.VirtualMachineMetrics;
|
||||||
|
import com.yammer.metrics.reporting.AbstractPollingReporter;
|
||||||
|
import com.yammer.metrics.stats.Snapshot;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.SortedMap;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapted from MetricsServlet.
|
||||||
|
*/
|
||||||
|
public class JsonMetricsReporter extends AbstractPollingReporter implements MetricProcessor<JsonMetricsReporter.Context> {
|
||||||
|
private final Clock clock = Clock.defaultClock();
|
||||||
|
private final VirtualMachineMetrics vm = VirtualMachineMetrics.getInstance();
|
||||||
|
private final String service;
|
||||||
|
private final MetricsRegistry registry;
|
||||||
|
private final JsonFactory factory = new JsonFactory();
|
||||||
|
|
||||||
|
private final String table;
|
||||||
|
private final String sunnylabsHost;
|
||||||
|
private final String host;
|
||||||
|
|
||||||
|
private final boolean includeVMMetrics;
|
||||||
|
|
||||||
|
public JsonMetricsReporter(String service, MetricsRegistry registry, String token, String sunnylabsHost) throws UnknownHostException {
|
||||||
|
this(service, registry, token, sunnylabsHost, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonMetricsReporter(String service, MetricsRegistry registry, String token, String sunnylabsHost, boolean includeVMMetrics) throws UnknownHostException {
|
||||||
|
super(registry, "jsonmetrics-reporter");
|
||||||
|
this.service = service;
|
||||||
|
this.registry = registry;
|
||||||
|
this.table = token;
|
||||||
|
this.sunnylabsHost = sunnylabsHost;
|
||||||
|
this.host = InetAddress.getLocalHost().getHostName();
|
||||||
|
this.includeVMMetrics = includeVMMetrics;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
URL http = new URL("https", sunnylabsHost, 443, "/report/metrics?t=" + table + "&h=" + host);
|
||||||
|
System.out.println("Reporting started to: " + http);
|
||||||
|
HttpURLConnection urlc = (HttpURLConnection) http.openConnection();
|
||||||
|
urlc.setDoOutput(true);
|
||||||
|
urlc.addRequestProperty("Content-Type", "application/json");
|
||||||
|
OutputStream outputStream = urlc.getOutputStream();
|
||||||
|
writeJson(outputStream);
|
||||||
|
outputStream.close();
|
||||||
|
System.out.println("Reporting complete: " + urlc.getResponseCode());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class Context {
|
||||||
|
final boolean showFullSamples;
|
||||||
|
final JsonGenerator json;
|
||||||
|
|
||||||
|
Context(JsonGenerator json, boolean showFullSamples) {
|
||||||
|
this.json = json;
|
||||||
|
this.showFullSamples = showFullSamples;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeJson(OutputStream out) throws IOException {
|
||||||
|
final JsonGenerator json = factory.createGenerator(out, JsonEncoding.UTF8);
|
||||||
|
json.writeStartObject();
|
||||||
|
if (includeVMMetrics) {
|
||||||
|
writeVmMetrics(json);
|
||||||
|
}
|
||||||
|
writeRegularMetrics(json, false);
|
||||||
|
json.writeEndObject();
|
||||||
|
json.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeVmMetrics(JsonGenerator json) throws IOException {
|
||||||
|
json.writeFieldName(service);
|
||||||
|
json.writeStartObject();
|
||||||
|
json.writeFieldName("jvm");
|
||||||
|
json.writeStartObject();
|
||||||
|
{
|
||||||
|
json.writeFieldName("vm");
|
||||||
|
json.writeStartObject();
|
||||||
|
{
|
||||||
|
json.writeStringField("name", vm.name());
|
||||||
|
json.writeStringField("version", vm.version());
|
||||||
|
}
|
||||||
|
json.writeEndObject();
|
||||||
|
|
||||||
|
json.writeFieldName("memory");
|
||||||
|
json.writeStartObject();
|
||||||
|
{
|
||||||
|
json.writeNumberField("totalInit", vm.totalInit());
|
||||||
|
json.writeNumberField("totalUsed", vm.totalUsed());
|
||||||
|
json.writeNumberField("totalMax", vm.totalMax());
|
||||||
|
json.writeNumberField("totalCommitted", vm.totalCommitted());
|
||||||
|
|
||||||
|
json.writeNumberField("heapInit", vm.heapInit());
|
||||||
|
json.writeNumberField("heapUsed", vm.heapUsed());
|
||||||
|
json.writeNumberField("heapMax", vm.heapMax());
|
||||||
|
json.writeNumberField("heapCommitted", vm.heapCommitted());
|
||||||
|
|
||||||
|
json.writeNumberField("heap_usage", vm.heapUsage());
|
||||||
|
json.writeNumberField("non_heap_usage", vm.nonHeapUsage());
|
||||||
|
json.writeFieldName("memory_pool_usages");
|
||||||
|
json.writeStartObject();
|
||||||
|
{
|
||||||
|
for (Map.Entry<String, Double> pool : vm.memoryPoolUsage().entrySet()) {
|
||||||
|
json.writeNumberField(pool.getKey(), pool.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
json.writeEndObject();
|
||||||
|
}
|
||||||
|
json.writeEndObject();
|
||||||
|
|
||||||
|
final Map<String, VirtualMachineMetrics.BufferPoolStats> bufferPoolStats = vm.getBufferPoolStats();
|
||||||
|
if (!bufferPoolStats.isEmpty()) {
|
||||||
|
json.writeFieldName("buffers");
|
||||||
|
json.writeStartObject();
|
||||||
|
{
|
||||||
|
json.writeFieldName("direct");
|
||||||
|
json.writeStartObject();
|
||||||
|
{
|
||||||
|
json.writeNumberField("count", bufferPoolStats.get("direct").getCount());
|
||||||
|
json.writeNumberField("memoryUsed", bufferPoolStats.get("direct").getMemoryUsed());
|
||||||
|
json.writeNumberField("totalCapacity", bufferPoolStats.get("direct").getTotalCapacity());
|
||||||
|
}
|
||||||
|
json.writeEndObject();
|
||||||
|
|
||||||
|
json.writeFieldName("mapped");
|
||||||
|
json.writeStartObject();
|
||||||
|
{
|
||||||
|
json.writeNumberField("count", bufferPoolStats.get("mapped").getCount());
|
||||||
|
json.writeNumberField("memoryUsed", bufferPoolStats.get("mapped").getMemoryUsed());
|
||||||
|
json.writeNumberField("totalCapacity", bufferPoolStats.get("mapped").getTotalCapacity());
|
||||||
|
}
|
||||||
|
json.writeEndObject();
|
||||||
|
}
|
||||||
|
json.writeEndObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
json.writeNumberField("daemon_thread_count", vm.daemonThreadCount());
|
||||||
|
json.writeNumberField("thread_count", vm.threadCount());
|
||||||
|
json.writeNumberField("current_time", clock.time());
|
||||||
|
json.writeNumberField("uptime", vm.uptime());
|
||||||
|
json.writeNumberField("fd_usage", vm.fileDescriptorUsage());
|
||||||
|
|
||||||
|
json.writeFieldName("thread-states");
|
||||||
|
json.writeStartObject();
|
||||||
|
{
|
||||||
|
for (Map.Entry<Thread.State, Double> entry : vm.threadStatePercentages()
|
||||||
|
.entrySet()) {
|
||||||
|
json.writeNumberField(entry.getKey().toString().toLowerCase(),
|
||||||
|
entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
json.writeEndObject();
|
||||||
|
|
||||||
|
json.writeFieldName("garbage-collectors");
|
||||||
|
json.writeStartObject();
|
||||||
|
{
|
||||||
|
for (Map.Entry<String, VirtualMachineMetrics.GarbageCollectorStats> entry : vm.garbageCollectors()
|
||||||
|
.entrySet()) {
|
||||||
|
json.writeFieldName(entry.getKey());
|
||||||
|
json.writeStartObject();
|
||||||
|
{
|
||||||
|
final VirtualMachineMetrics.GarbageCollectorStats gc = entry.getValue();
|
||||||
|
json.writeNumberField("runs", gc.getRuns());
|
||||||
|
json.writeNumberField("time", gc.getTime(TimeUnit.MILLISECONDS));
|
||||||
|
}
|
||||||
|
json.writeEndObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
json.writeEndObject();
|
||||||
|
}
|
||||||
|
json.writeEndObject();
|
||||||
|
json.writeEndObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeRegularMetrics(JsonGenerator json, boolean showFullSamples) throws IOException {
|
||||||
|
for (Map.Entry<String, SortedMap<MetricName, Metric>> entry : registry.groupedMetrics().entrySet()) {
|
||||||
|
for (Map.Entry<MetricName, Metric> subEntry : entry.getValue().entrySet()) {
|
||||||
|
json.writeFieldName(sanitize(subEntry.getKey()));
|
||||||
|
try {
|
||||||
|
subEntry.getValue()
|
||||||
|
.processWith(this,
|
||||||
|
subEntry.getKey(),
|
||||||
|
new Context(json, showFullSamples));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processHistogram(MetricName name, Histogram histogram, Context context) throws Exception {
|
||||||
|
final JsonGenerator json = context.json;
|
||||||
|
json.writeStartObject();
|
||||||
|
{
|
||||||
|
json.writeNumberField("count", histogram.count());
|
||||||
|
writeSummarizable(histogram, json);
|
||||||
|
writeSampling(histogram, json);
|
||||||
|
if (context.showFullSamples) {
|
||||||
|
json.writeObjectField("values", histogram.getSnapshot().getValues());
|
||||||
|
}
|
||||||
|
histogram.clear();
|
||||||
|
}
|
||||||
|
json.writeEndObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processCounter(MetricName name, Counter counter, Context context) throws Exception {
|
||||||
|
final JsonGenerator json = context.json;
|
||||||
|
json.writeNumber(counter.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processGauge(MetricName name, Gauge<?> gauge, Context context) throws Exception {
|
||||||
|
final JsonGenerator json = context.json;
|
||||||
|
json.writeObject(evaluateGauge(gauge));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processMeter(MetricName name, Metered meter, Context context) throws Exception {
|
||||||
|
final JsonGenerator json = context.json;
|
||||||
|
json.writeStartObject();
|
||||||
|
{
|
||||||
|
writeMeteredFields(meter, json);
|
||||||
|
}
|
||||||
|
json.writeEndObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processTimer(MetricName name, Timer timer, Context context) throws Exception {
|
||||||
|
final JsonGenerator json = context.json;
|
||||||
|
json.writeStartObject();
|
||||||
|
{
|
||||||
|
json.writeFieldName("duration");
|
||||||
|
json.writeStartObject();
|
||||||
|
{
|
||||||
|
json.writeStringField("unit", timer.durationUnit().toString().toLowerCase());
|
||||||
|
writeSummarizable(timer, json);
|
||||||
|
writeSampling(timer, json);
|
||||||
|
if (context.showFullSamples) {
|
||||||
|
json.writeObjectField("values", timer.getSnapshot().getValues());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
json.writeEndObject();
|
||||||
|
|
||||||
|
json.writeFieldName("rate");
|
||||||
|
json.writeStartObject();
|
||||||
|
{
|
||||||
|
writeMeteredFields(timer, json);
|
||||||
|
}
|
||||||
|
json.writeEndObject();
|
||||||
|
}
|
||||||
|
json.writeEndObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object evaluateGauge(Gauge<?> gauge) {
|
||||||
|
try {
|
||||||
|
return gauge.value();
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
return "error reading gauge: " + e.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void writeSummarizable(Summarizable metric, JsonGenerator json) throws IOException {
|
||||||
|
json.writeNumberField("min", metric.min());
|
||||||
|
json.writeNumberField("max", metric.max());
|
||||||
|
json.writeNumberField("mean", metric.mean());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void writeSampling(Sampling metric, JsonGenerator json) throws IOException {
|
||||||
|
final Snapshot snapshot = metric.getSnapshot();
|
||||||
|
json.writeNumberField("median", snapshot.getMedian());
|
||||||
|
json.writeNumberField("p75", snapshot.get75thPercentile());
|
||||||
|
json.writeNumberField("p95", snapshot.get95thPercentile());
|
||||||
|
json.writeNumberField("p99", snapshot.get99thPercentile());
|
||||||
|
json.writeNumberField("p999", snapshot.get999thPercentile());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void writeMeteredFields(Metered metered, JsonGenerator json) throws IOException {
|
||||||
|
json.writeNumberField("count", metered.count());
|
||||||
|
json.writeNumberField("mean", metered.meanRate());
|
||||||
|
json.writeNumberField("m1", metered.oneMinuteRate());
|
||||||
|
json.writeNumberField("m5", metered.fiveMinuteRate());
|
||||||
|
json.writeNumberField("m15", metered.fifteenMinuteRate());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Pattern SIMPLE_NAMES = Pattern.compile("[^a-zA-Z0-9_.\\-~]");
|
||||||
|
|
||||||
|
private String sanitize(MetricName metricName) {
|
||||||
|
return SIMPLE_NAMES.matcher(metricName.getGroup() + "." + metricName.getName()).replaceAll("_");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package org.whispersystems.textsecuregcm.metrics;
|
||||||
|
|
||||||
|
|
||||||
|
import com.yammer.metrics.core.Gauge;
|
||||||
|
import org.whispersystems.textsecuregcm.util.Pair;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public abstract class NetworkGauge extends Gauge<Long> {
|
||||||
|
|
||||||
|
protected Pair<Long, Long> getSentReceived() throws IOException {
|
||||||
|
File proc = new File("/proc/net/dev");
|
||||||
|
BufferedReader reader = new BufferedReader(new FileReader(proc));
|
||||||
|
String header = reader.readLine();
|
||||||
|
String header2 = reader.readLine();
|
||||||
|
|
||||||
|
long bytesSent = 0;
|
||||||
|
long bytesReceived = 0;
|
||||||
|
|
||||||
|
String interfaceStats;
|
||||||
|
|
||||||
|
while ((interfaceStats = reader.readLine()) != null) {
|
||||||
|
String[] stats = interfaceStats.split("\\s+");
|
||||||
|
|
||||||
|
if (!stats[1].equals("lo:")) {
|
||||||
|
bytesReceived += Long.parseLong(stats[2]);
|
||||||
|
bytesSent += Long.parseLong(stats[10]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Pair<>(bytesSent, bytesReceived);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package org.whispersystems.textsecuregcm.metrics;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.whispersystems.textsecuregcm.util.Pair;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class NetworkReceivedGauge extends NetworkGauge {
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(NetworkSentGauge.class);
|
||||||
|
|
||||||
|
private long lastTimestamp;
|
||||||
|
private long lastReceived;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long value() {
|
||||||
|
try {
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
Pair<Long, Long> sentAndReceived = getSentReceived();
|
||||||
|
long result = 0;
|
||||||
|
|
||||||
|
if (lastTimestamp != 0) {
|
||||||
|
result = sentAndReceived.second() - lastReceived;
|
||||||
|
lastReceived = sentAndReceived.second();
|
||||||
|
}
|
||||||
|
|
||||||
|
lastTimestamp = timestamp;
|
||||||
|
return result;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.warn("NetworkReceivedGauge", e);
|
||||||
|
return -1L;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package org.whispersystems.textsecuregcm.metrics;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.whispersystems.textsecuregcm.util.Pair;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class NetworkSentGauge extends NetworkGauge {
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(NetworkSentGauge.class);
|
||||||
|
|
||||||
|
private long lastTimestamp;
|
||||||
|
private long lastSent;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long value() {
|
||||||
|
try {
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
Pair<Long, Long> sentAndReceived = getSentReceived();
|
||||||
|
long result = 0;
|
||||||
|
|
||||||
|
if (lastTimestamp != 0) {
|
||||||
|
result = sentAndReceived.first() - lastSent;
|
||||||
|
lastSent = sentAndReceived.first();
|
||||||
|
}
|
||||||
|
|
||||||
|
lastTimestamp = timestamp;
|
||||||
|
return result;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.warn("NetworkSentGauge", e);
|
||||||
|
return -1L;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,7 +28,7 @@ import java.util.List;
|
|||||||
|
|
||||||
public class Account implements Serializable {
|
public class Account implements Serializable {
|
||||||
|
|
||||||
public static final int MEMCACHE_VERION = 2;
|
public static final int MEMCACHE_VERION = 3;
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private long id;
|
private long id;
|
||||||
@@ -42,16 +42,14 @@ public class Account implements Serializable {
|
|||||||
@JsonProperty
|
@JsonProperty
|
||||||
private List<Device> devices = new LinkedList<>();
|
private List<Device> devices = new LinkedList<>();
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private String identityKey;
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private Optional<Device> authenticatedDevice;
|
private Optional<Device> authenticatedDevice;
|
||||||
|
|
||||||
public Account() {}
|
public Account() {}
|
||||||
|
|
||||||
public Account(String number, boolean supportsSms) {
|
|
||||||
this.number = number;
|
|
||||||
this.supportsSms = supportsSms;
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public Account(String number, boolean supportsSms, List<Device> devices) {
|
public Account(String number, boolean supportsSms, List<Device> devices) {
|
||||||
this.number = number;
|
this.number = number;
|
||||||
@@ -142,4 +140,12 @@ public class Account implements Serializable {
|
|||||||
public Optional<String> getRelay() {
|
public Optional<String> getRelay() {
|
||||||
return Optional.absent();
|
return Optional.absent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setIdentityKey(String identityKey) {
|
||||||
|
this.identityKey = identityKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIdentityKey() {
|
||||||
|
return identityKey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package org.whispersystems.textsecuregcm.tests.controllers;
|
||||||
|
|
||||||
|
import com.sun.jersey.api.client.ClientResponse;
|
||||||
|
import com.yammer.dropwizard.testing.ResourceTest;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
|
import org.mockito.stubbing.Answer;
|
||||||
|
import org.whispersystems.textsecuregcm.controllers.DirectoryController;
|
||||||
|
import org.whispersystems.textsecuregcm.entities.ClientContactTokens;
|
||||||
|
import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
||||||
|
import org.whispersystems.textsecuregcm.limits.RateLimiters;
|
||||||
|
import org.whispersystems.textsecuregcm.storage.DirectoryManager;
|
||||||
|
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||||
|
import org.whispersystems.textsecuregcm.util.Base64;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.fest.assertions.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.Matchers.anyList;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
public class DirectoryControllerTest extends ResourceTest {
|
||||||
|
|
||||||
|
private RateLimiters rateLimiters = mock(RateLimiters.class );
|
||||||
|
private RateLimiter rateLimiter = mock(RateLimiter.class );
|
||||||
|
private DirectoryManager directoryManager = mock(DirectoryManager.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUpResources() throws Exception {
|
||||||
|
addProvider(AuthHelper.getAuthenticator());
|
||||||
|
|
||||||
|
when(rateLimiters.getContactsLimiter()).thenReturn(rateLimiter);
|
||||||
|
when(directoryManager.get(anyList())).thenAnswer(new Answer<List<byte[]>>() {
|
||||||
|
@Override
|
||||||
|
public List<byte[]> answer(InvocationOnMock invocationOnMock) throws Throwable {
|
||||||
|
List<byte[]> query = (List<byte[]>) invocationOnMock.getArguments()[0];
|
||||||
|
List<byte[]> response = new LinkedList<>(query);
|
||||||
|
response.remove(0);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
addResource(new DirectoryController(rateLimiters, directoryManager));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testContactIntersection() throws Exception {
|
||||||
|
List<String> tokens = new LinkedList<String>() {{
|
||||||
|
add(Base64.encodeBytes("foo".getBytes()));
|
||||||
|
add(Base64.encodeBytes("bar".getBytes()));
|
||||||
|
add(Base64.encodeBytes("baz".getBytes()));
|
||||||
|
}};
|
||||||
|
|
||||||
|
List<String> expectedResponse = new LinkedList<>(tokens);
|
||||||
|
expectedResponse.remove(0);
|
||||||
|
|
||||||
|
ClientResponse response =
|
||||||
|
client().resource("/v1/directory/tokens/")
|
||||||
|
.entity(new ClientContactTokens(tokens))
|
||||||
|
.type(MediaType.APPLICATION_JSON_TYPE)
|
||||||
|
.header("Authorization",
|
||||||
|
AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER,
|
||||||
|
AuthHelper.VALID_PASSWORD))
|
||||||
|
.put(ClientResponse.class);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
assertThat(response.getEntity(ClientContactTokens.class).getContacts()).isEqualTo(expectedResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,8 +4,10 @@ import com.google.common.base.Optional;
|
|||||||
import com.sun.jersey.api.client.ClientResponse;
|
import com.sun.jersey.api.client.ClientResponse;
|
||||||
import com.yammer.dropwizard.testing.ResourceTest;
|
import com.yammer.dropwizard.testing.ResourceTest;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.whispersystems.textsecuregcm.controllers.KeysController;
|
import org.whispersystems.textsecuregcm.controllers.KeysController;
|
||||||
import org.whispersystems.textsecuregcm.entities.PreKey;
|
import org.whispersystems.textsecuregcm.entities.PreKey;
|
||||||
|
import org.whispersystems.textsecuregcm.entities.PreKeyList;
|
||||||
import org.whispersystems.textsecuregcm.entities.PreKeyStatus;
|
import org.whispersystems.textsecuregcm.entities.PreKeyStatus;
|
||||||
import org.whispersystems.textsecuregcm.entities.UnstructuredPreKeyList;
|
import org.whispersystems.textsecuregcm.entities.UnstructuredPreKeyList;
|
||||||
import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
import org.whispersystems.textsecuregcm.limits.RateLimiter;
|
||||||
@@ -16,6 +18,7 @@ import org.whispersystems.textsecuregcm.storage.Device;
|
|||||||
import org.whispersystems.textsecuregcm.storage.Keys;
|
import org.whispersystems.textsecuregcm.storage.Keys;
|
||||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -30,11 +33,13 @@ public class KeyControllerTest extends ResourceTest {
|
|||||||
private final int SAMPLE_REGISTRATION_ID = 999;
|
private final int SAMPLE_REGISTRATION_ID = 999;
|
||||||
private final int SAMPLE_REGISTRATION_ID2 = 1002;
|
private final int SAMPLE_REGISTRATION_ID2 = 1002;
|
||||||
|
|
||||||
private final PreKey SAMPLE_KEY = new PreKey(1, EXISTS_NUMBER, Device.MASTER_ID, 1234, "test1", "test2", false);
|
private final PreKey SAMPLE_KEY = new PreKey(1, EXISTS_NUMBER, Device.MASTER_ID, 1234, "test1", "test2", false);
|
||||||
private final PreKey SAMPLE_KEY2 = new PreKey(2, EXISTS_NUMBER, 2, 5667, "test3", "test4", false );
|
private final PreKey SAMPLE_KEY2 = new PreKey(2, EXISTS_NUMBER, 2, 5667, "test3", "test4", false );
|
||||||
private final PreKey SAMPLE_KEY3 = new PreKey(3, EXISTS_NUMBER, 3, 334, "test5", "test6", false);
|
private final PreKey SAMPLE_KEY3 = new PreKey(3, EXISTS_NUMBER, 3, 334, "test5", "test6", false );
|
||||||
private final Keys keys = mock(Keys.class );
|
private final Keys keys = mock(Keys.class );
|
||||||
private final AccountsManager accounts = mock(AccountsManager.class);
|
private final AccountsManager accounts = mock(AccountsManager.class);
|
||||||
|
private final Account existsAccount = mock(Account.class );
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setUpResources() {
|
protected void setUpResources() {
|
||||||
@@ -46,7 +51,6 @@ public class KeyControllerTest extends ResourceTest {
|
|||||||
Device sampleDevice = mock(Device.class );
|
Device sampleDevice = mock(Device.class );
|
||||||
Device sampleDevice2 = mock(Device.class);
|
Device sampleDevice2 = mock(Device.class);
|
||||||
Device sampleDevice3 = mock(Device.class);
|
Device sampleDevice3 = mock(Device.class);
|
||||||
Account existsAccount = mock(Account.class);
|
|
||||||
|
|
||||||
when(sampleDevice.getRegistrationId()).thenReturn(SAMPLE_REGISTRATION_ID);
|
when(sampleDevice.getRegistrationId()).thenReturn(SAMPLE_REGISTRATION_ID);
|
||||||
when(sampleDevice2.getRegistrationId()).thenReturn(SAMPLE_REGISTRATION_ID2);
|
when(sampleDevice2.getRegistrationId()).thenReturn(SAMPLE_REGISTRATION_ID2);
|
||||||
@@ -76,6 +80,8 @@ public class KeyControllerTest extends ResourceTest {
|
|||||||
when(keys.get(EXISTS_NUMBER)).thenReturn(Optional.of(new UnstructuredPreKeyList(allKeys)));
|
when(keys.get(EXISTS_NUMBER)).thenReturn(Optional.of(new UnstructuredPreKeyList(allKeys)));
|
||||||
when(keys.getCount(eq(AuthHelper.VALID_NUMBER), eq(1L))).thenReturn(5);
|
when(keys.getCount(eq(AuthHelper.VALID_NUMBER), eq(1L))).thenReturn(5);
|
||||||
|
|
||||||
|
when(AuthHelper.VALID_ACCOUNT.getIdentityKey()).thenReturn(null);
|
||||||
|
|
||||||
addResource(new KeysController(rateLimiters, keys, accounts, null));
|
addResource(new KeysController(rateLimiters, keys, accounts, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,4 +171,42 @@ public class KeyControllerTest extends ResourceTest {
|
|||||||
assertThat(response.getClientResponseStatus().getStatusCode()).isEqualTo(401);
|
assertThat(response.getClientResponseStatus().getStatusCode()).isEqualTo(401);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void putKeysTest() throws Exception {
|
||||||
|
final PreKey newKey = new PreKey(0, null, 1L, 31337, "foobar", "foobarbaz", false);
|
||||||
|
final PreKey lastResortKey = new PreKey(0, null, 1L, 0xFFFFFF, "fooz", "foobarbaz", false);
|
||||||
|
|
||||||
|
List<PreKey> preKeys = new LinkedList<PreKey>() {{
|
||||||
|
add(newKey);
|
||||||
|
}};
|
||||||
|
|
||||||
|
PreKeyList preKeyList = new PreKeyList();
|
||||||
|
preKeyList.setKeys(preKeys);
|
||||||
|
preKeyList.setLastResortKey(lastResortKey);
|
||||||
|
|
||||||
|
ClientResponse response =
|
||||||
|
client().resource("/v1/keys")
|
||||||
|
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
|
||||||
|
.type(MediaType.APPLICATION_JSON_TYPE)
|
||||||
|
.put(ClientResponse.class, preKeyList);
|
||||||
|
|
||||||
|
assertThat(response.getClientResponseStatus().getStatusCode()).isEqualTo(204);
|
||||||
|
|
||||||
|
ArgumentCaptor<List> listCaptor = ArgumentCaptor.forClass(List.class );
|
||||||
|
ArgumentCaptor<PreKey> lastResortCaptor = ArgumentCaptor.forClass(PreKey.class);
|
||||||
|
verify(keys).store(eq(AuthHelper.VALID_NUMBER), eq(1L), listCaptor.capture(), lastResortCaptor.capture());
|
||||||
|
|
||||||
|
List<PreKey> capturedList = listCaptor.getValue();
|
||||||
|
assertThat(capturedList.size() == 1);
|
||||||
|
assertThat(capturedList.get(0).getIdentityKey().equals("foobarbaz"));
|
||||||
|
assertThat(capturedList.get(0).getKeyId() == 31337);
|
||||||
|
assertThat(capturedList.get(0).getPublicKey().equals("foobar"));
|
||||||
|
|
||||||
|
assertThat(lastResortCaptor.getValue().getPublicKey().equals("fooz"));
|
||||||
|
assertThat(lastResortCaptor.getValue().getIdentityKey().equals("foobarbaz"));
|
||||||
|
|
||||||
|
verify(AuthHelper.VALID_ACCOUNT).setIdentityKey(eq("foobarbaz"));
|
||||||
|
verify(accounts).update(AuthHelper.VALID_ACCOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -27,20 +27,20 @@ public class AuthHelper {
|
|||||||
public static final String INVVALID_NUMBER = "+14151111111";
|
public static final String INVVALID_NUMBER = "+14151111111";
|
||||||
public static final String INVALID_PASSWORD = "bar";
|
public static final String INVALID_PASSWORD = "bar";
|
||||||
|
|
||||||
public static MultiBasicAuthProvider<FederatedPeer, Account> getAuthenticator() {
|
public static AccountsManager ACCOUNTS_MANAGER = mock(AccountsManager.class );
|
||||||
AccountsManager accounts = mock(AccountsManager.class );
|
public static Account VALID_ACCOUNT = mock(Account.class );
|
||||||
Account account = mock(Account.class );
|
public static Device VALID_DEVICE = mock(Device.class );
|
||||||
Device device = mock(Device.class );
|
public static AuthenticationCredentials VALID_CREDENTIALS = mock(AuthenticationCredentials.class);
|
||||||
AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
|
||||||
|
|
||||||
when(credentials.verify("foo")).thenReturn(true);
|
public static MultiBasicAuthProvider<FederatedPeer, Account> getAuthenticator() {
|
||||||
when(device.getAuthenticationCredentials()).thenReturn(credentials);
|
when(VALID_CREDENTIALS.verify("foo")).thenReturn(true);
|
||||||
when(device.getId()).thenReturn(1L);
|
when(VALID_DEVICE.getAuthenticationCredentials()).thenReturn(VALID_CREDENTIALS);
|
||||||
when(account.getDevice(anyLong())).thenReturn(Optional.of(device));
|
when(VALID_DEVICE.getId()).thenReturn(1L);
|
||||||
when(account.getNumber()).thenReturn(VALID_NUMBER);
|
when(VALID_ACCOUNT.getDevice(anyLong())).thenReturn(Optional.of(VALID_DEVICE));
|
||||||
when(account.getAuthenticatedDevice()).thenReturn(Optional.of(device));
|
when(VALID_ACCOUNT.getNumber()).thenReturn(VALID_NUMBER);
|
||||||
when(account.getRelay()).thenReturn(Optional.<String>absent());
|
when(VALID_ACCOUNT.getAuthenticatedDevice()).thenReturn(Optional.of(VALID_DEVICE));
|
||||||
when(accounts.get(VALID_NUMBER)).thenReturn(Optional.of(account));
|
when(VALID_ACCOUNT.getRelay()).thenReturn(Optional.<String>absent());
|
||||||
|
when(ACCOUNTS_MANAGER.get(VALID_NUMBER)).thenReturn(Optional.of(VALID_ACCOUNT));
|
||||||
|
|
||||||
List<FederatedPeer> peer = new LinkedList<FederatedPeer>() {{
|
List<FederatedPeer> peer = new LinkedList<FederatedPeer>() {{
|
||||||
add(new FederatedPeer("cyanogen", "https://foo", "foofoo", "bazzzzz"));
|
add(new FederatedPeer("cyanogen", "https://foo", "foofoo", "bazzzzz"));
|
||||||
@@ -51,7 +51,7 @@ public class AuthHelper {
|
|||||||
|
|
||||||
return new MultiBasicAuthProvider<>(new FederatedPeerAuthenticator(federationConfiguration),
|
return new MultiBasicAuthProvider<>(new FederatedPeerAuthenticator(federationConfiguration),
|
||||||
FederatedPeer.class,
|
FederatedPeer.class,
|
||||||
new AccountAuthenticator(accounts),
|
new AccountAuthenticator(ACCOUNTS_MANAGER),
|
||||||
Account.class, "WhisperServer");
|
Account.class, "WhisperServer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user