mirror of
				https://github.com/oxen-io/session-android.git
				synced 2025-11-04 01:01:22 +00:00 
			
		
		
		
	Support for server federation.
This commit is contained in:
		@@ -6,9 +6,10 @@ option java_outer_classname = "PushMessageProtos";
 | 
			
		||||
message IncomingPushMessageSignal {
 | 
			
		||||
  optional uint32 type = 1;
 | 
			
		||||
  optional string source = 2;
 | 
			
		||||
  repeated string destinations = 3;
 | 
			
		||||
  optional uint64 timestamp = 4;
 | 
			
		||||
  optional bytes message = 5; // Contains an encrypted IncomingPushMessageContent
 | 
			
		||||
  optional string relay = 3;
 | 
			
		||||
  repeated string destinations = 4;
 | 
			
		||||
  optional uint64 timestamp = 5;
 | 
			
		||||
  optional bytes message = 6; // Contains an encrypted PushMessageContent
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message PushMessageContent {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
package org.whispersystems.textsecure;
 | 
			
		||||
 | 
			
		||||
public class Release {
 | 
			
		||||
  public static final String PUSH_SERVICE_URL = "https://gcm.textsecure.whispersystems.org";
 | 
			
		||||
  public static final String PUSH_SERVICE_URL = "https://federated.textsecure.whispersystems.org";
 | 
			
		||||
//  public static final String PUSH_SERVICE_URL = "http://192.168.1.135:8080";
 | 
			
		||||
  public static final boolean ENFORCE_SSL     = true;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -132,6 +132,9 @@ public class PreKeyUtil {
 | 
			
		||||
  private static class PreKeyRecordIdComparator implements Comparator<String> {
 | 
			
		||||
    @Override
 | 
			
		||||
    public int compare(String lhs, String rhs) {
 | 
			
		||||
      if      (lhs.equals(PreKeyIndex.FILE_NAME)) return -1;
 | 
			
		||||
      else if (rhs.equals(PreKeyIndex.FILE_NAME)) return 1;
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        long lhsLong = Long.parseLong(lhs);
 | 
			
		||||
        long rhsLong = Long.parseLong(rhs);
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ import android.net.Uri;
 | 
			
		||||
import android.provider.ContactsContract.CommonDataKinds.Phone;
 | 
			
		||||
import android.util.Log;
 | 
			
		||||
 | 
			
		||||
import org.whispersystems.textsecure.push.ContactTokenDetails;
 | 
			
		||||
import org.whispersystems.textsecure.util.Base64;
 | 
			
		||||
import org.whispersystems.textsecure.util.PhoneNumberFormatter;
 | 
			
		||||
import org.whispersystems.textsecure.util.Util;
 | 
			
		||||
@@ -29,11 +30,15 @@ public class Directory {
 | 
			
		||||
  private static final String ID           = "_id";
 | 
			
		||||
  private static final String TOKEN        = "token";
 | 
			
		||||
  private static final String REGISTERED   = "registered";
 | 
			
		||||
  private static final String RELAY        = "relay";
 | 
			
		||||
  private static final String SUPPORTS_SMS = "supports_sms";
 | 
			
		||||
  private static final String TIMESTAMP    = "timestamp";
 | 
			
		||||
  private static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + ID + " INTEGER PRIMARY KEY, " +
 | 
			
		||||
                                             TOKEN + " TEXT UNIQUE, " + REGISTERED + " INTEGER, " +
 | 
			
		||||
                                             SUPPORTS_SMS + " INTEGER, " + TIMESTAMP + " INTEGER);";
 | 
			
		||||
                                             TOKEN        + " TEXT UNIQUE, " +
 | 
			
		||||
                                             REGISTERED   + " INTEGER, " +
 | 
			
		||||
                                             RELAY        + " TEXT " +
 | 
			
		||||
                                             SUPPORTS_SMS + " INTEGER, " +
 | 
			
		||||
                                             TIMESTAMP    + " INTEGER);";
 | 
			
		||||
 | 
			
		||||
  private static Directory instance;
 | 
			
		||||
 | 
			
		||||
@@ -79,27 +84,49 @@ public class Directory {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setToken(String token, boolean active) {
 | 
			
		||||
  public String getRelay(String e164number) {
 | 
			
		||||
    String         token    = getToken(e164number);
 | 
			
		||||
    SQLiteDatabase database = databaseHelper.getReadableDatabase();
 | 
			
		||||
    Cursor         cursor   = null;
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      cursor = database.query(TABLE_NAME, null, TOKEN + " = ?", new String[]{token}, null, null, null);
 | 
			
		||||
 | 
			
		||||
      if (cursor != null && cursor.moveToFirst()) {
 | 
			
		||||
        return cursor.getString(cursor.getColumnIndexOrThrow(RELAY));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return null;
 | 
			
		||||
    } finally {
 | 
			
		||||
      if (cursor != null)
 | 
			
		||||
        cursor.close();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setToken(ContactTokenDetails token, boolean active) {
 | 
			
		||||
    SQLiteDatabase db     = databaseHelper.getWritableDatabase();
 | 
			
		||||
    ContentValues  values = new ContentValues();
 | 
			
		||||
    values.put(TOKEN, token);
 | 
			
		||||
    values.put(TOKEN, token.getToken());
 | 
			
		||||
    values.put(RELAY, token.getRelay());
 | 
			
		||||
    values.put(REGISTERED, active ? 1 : 0);
 | 
			
		||||
    values.put(SUPPORTS_SMS, token.isSupportsSms());
 | 
			
		||||
    values.put(TIMESTAMP, System.currentTimeMillis());
 | 
			
		||||
    db.replace(TABLE_NAME, null, values);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setTokens(List<String> activeTokens, Collection<String> inactiveTokens) {
 | 
			
		||||
  public void setTokens(List<ContactTokenDetails> activeTokens, Collection<String> inactiveTokens) {
 | 
			
		||||
    long timestamp    = System.currentTimeMillis();
 | 
			
		||||
    SQLiteDatabase db = databaseHelper.getWritableDatabase();
 | 
			
		||||
    db.beginTransaction();
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      for (String token : activeTokens) {
 | 
			
		||||
      for (ContactTokenDetails token : activeTokens) {
 | 
			
		||||
        Log.w("Directory", "Adding active token: " + token);
 | 
			
		||||
        ContentValues values = new ContentValues();
 | 
			
		||||
        values.put(TOKEN, token);
 | 
			
		||||
        values.put(TOKEN, token.getToken());
 | 
			
		||||
        values.put(REGISTERED, 1);
 | 
			
		||||
        values.put(TIMESTAMP, timestamp);
 | 
			
		||||
        values.put(RELAY, token.getRelay());
 | 
			
		||||
        db.replace(TABLE_NAME, null, values);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@@ -125,7 +152,7 @@ public class Directory {
 | 
			
		||||
    try {
 | 
			
		||||
      cursor = context.getContentResolver().query(uri, new String[] {Phone.NUMBER}, null, null, null);
 | 
			
		||||
 | 
			
		||||
      while (cursor.moveToNext()) {
 | 
			
		||||
      while (cursor != null && cursor.moveToNext()) {
 | 
			
		||||
        String rawNumber = cursor.getString(0);
 | 
			
		||||
 | 
			
		||||
        if (rawNumber != null) {
 | 
			
		||||
@@ -134,12 +161,13 @@ public class Directory {
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      cursor.close();
 | 
			
		||||
      if (cursor != null)
 | 
			
		||||
        cursor.close();
 | 
			
		||||
 | 
			
		||||
      cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, new String[] {TOKEN},
 | 
			
		||||
                                                          null, null, null, null, null);
 | 
			
		||||
 | 
			
		||||
      while (cursor.moveToNext()) {
 | 
			
		||||
      while (cursor != null && cursor.moveToNext()) {
 | 
			
		||||
        results.add(cursor.getString(0));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,41 @@
 | 
			
		||||
package org.whispersystems.textsecure.push;
 | 
			
		||||
 | 
			
		||||
import com.google.thoughtcrimegson.Gson;
 | 
			
		||||
 | 
			
		||||
public class ContactTokenDetails {
 | 
			
		||||
 | 
			
		||||
  private String  token;
 | 
			
		||||
  private String  relay;
 | 
			
		||||
  private boolean supportsSms;
 | 
			
		||||
 | 
			
		||||
  public ContactTokenDetails() {}
 | 
			
		||||
 | 
			
		||||
  public ContactTokenDetails(String token) {
 | 
			
		||||
    this.token = token;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public ContactTokenDetails(String token, String relay) {
 | 
			
		||||
    this.token = token;
 | 
			
		||||
    this.relay = relay;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public String getToken() {
 | 
			
		||||
    return token;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public String getRelay() {
 | 
			
		||||
    return relay;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setRelay(String relay) {
 | 
			
		||||
    this.relay = relay;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public boolean isSupportsSms() {
 | 
			
		||||
    return supportsSms;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public String toString() {
 | 
			
		||||
    return new Gson().toJson(this);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,14 @@
 | 
			
		||||
package org.whispersystems.textsecure.push;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class ContactTokenDetailsList {
 | 
			
		||||
 | 
			
		||||
  private List<ContactTokenDetails> contacts;
 | 
			
		||||
 | 
			
		||||
  public ContactTokenDetailsList() {}
 | 
			
		||||
 | 
			
		||||
  public List<ContactTokenDetails> getContacts() {
 | 
			
		||||
    return contacts;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -43,14 +43,16 @@ public class IncomingPushMessage implements PushMessage, Parcelable {
 | 
			
		||||
  private List<String> destinations;
 | 
			
		||||
  private byte[]       message;
 | 
			
		||||
  private long         timestamp;
 | 
			
		||||
  private String       relay;
 | 
			
		||||
 | 
			
		||||
  private IncomingPushMessage(IncomingPushMessage message, byte[] body) {
 | 
			
		||||
    this.type         = message.type;
 | 
			
		||||
    this.source       = message.source;
 | 
			
		||||
    this.timestamp    = message.timestamp;
 | 
			
		||||
    this.relay        = message.relay;
 | 
			
		||||
    this.message      = body;
 | 
			
		||||
    this.destinations = new LinkedList<String>();
 | 
			
		||||
    this.destinations.addAll(message.destinations);
 | 
			
		||||
    this.message   = body;
 | 
			
		||||
    this.timestamp = message.timestamp;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public IncomingPushMessage(IncomingPushMessageSignal signal) {
 | 
			
		||||
@@ -59,12 +61,18 @@ public class IncomingPushMessage implements PushMessage, Parcelable {
 | 
			
		||||
    this.destinations = signal.getDestinationsList();
 | 
			
		||||
    this.message      = signal.getMessage().toByteArray();
 | 
			
		||||
    this.timestamp    = signal.getTimestamp();
 | 
			
		||||
    this.relay        = signal.getRelay();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public IncomingPushMessage(Parcel in) {
 | 
			
		||||
    this.destinations = new LinkedList<String>();
 | 
			
		||||
    this.type   = in.readInt();
 | 
			
		||||
    this.source = in.readString();
 | 
			
		||||
 | 
			
		||||
    if (in.readInt() == 1) {
 | 
			
		||||
      this.relay  = in.readString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    in.readStringList(destinations);
 | 
			
		||||
    this.message = new byte[in.readInt()];
 | 
			
		||||
    in.readByteArray(this.message);
 | 
			
		||||
@@ -82,6 +90,10 @@ public class IncomingPushMessage implements PushMessage, Parcelable {
 | 
			
		||||
    this.timestamp    = timestamp;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public String getRelay() {
 | 
			
		||||
    return relay;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public long getTimestampMillis() {
 | 
			
		||||
    return timestamp;
 | 
			
		||||
  }
 | 
			
		||||
@@ -107,6 +119,10 @@ public class IncomingPushMessage implements PushMessage, Parcelable {
 | 
			
		||||
  public void writeToParcel(Parcel dest, int flags) {
 | 
			
		||||
    dest.writeInt(type);
 | 
			
		||||
    dest.writeString(source);
 | 
			
		||||
    dest.writeInt(relay == null ? 0 : 1);
 | 
			
		||||
    if (relay != null) {
 | 
			
		||||
      dest.writeString(relay);
 | 
			
		||||
    }
 | 
			
		||||
    dest.writeStringList(destinations);
 | 
			
		||||
    dest.writeInt(message.length);
 | 
			
		||||
    dest.writeByteArray(message);
 | 
			
		||||
 
 | 
			
		||||
@@ -23,8 +23,14 @@ public class OutgoingPushMessage implements PushMessage {
 | 
			
		||||
  private int    type;
 | 
			
		||||
  private String destination;
 | 
			
		||||
  private String body;
 | 
			
		||||
  private String relay;
 | 
			
		||||
 | 
			
		||||
  public OutgoingPushMessage(String destination, byte[] body, int type) {
 | 
			
		||||
    this(null, destination, body, type);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public OutgoingPushMessage(String relay, String destination, byte[] body, int type) {
 | 
			
		||||
    this.relay       = relay;
 | 
			
		||||
    this.destination = destination;
 | 
			
		||||
    this.body        = Base64.encodeBytes(body);
 | 
			
		||||
    this.type        = type;
 | 
			
		||||
@@ -41,4 +47,8 @@ public class OutgoingPushMessage implements PushMessage {
 | 
			
		||||
  public int getType() {
 | 
			
		||||
    return type;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public String getRelay() {
 | 
			
		||||
    return relay;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,16 +19,20 @@ public final class PushMessageProtos {
 | 
			
		||||
    boolean hasSource();
 | 
			
		||||
    String getSource();
 | 
			
		||||
    
 | 
			
		||||
    // repeated string destinations = 3;
 | 
			
		||||
    // optional string relay = 3;
 | 
			
		||||
    boolean hasRelay();
 | 
			
		||||
    String getRelay();
 | 
			
		||||
    
 | 
			
		||||
    // repeated string destinations = 4;
 | 
			
		||||
    java.util.List<String> getDestinationsList();
 | 
			
		||||
    int getDestinationsCount();
 | 
			
		||||
    String getDestinations(int index);
 | 
			
		||||
    
 | 
			
		||||
    // optional uint64 timestamp = 4;
 | 
			
		||||
    // optional uint64 timestamp = 5;
 | 
			
		||||
    boolean hasTimestamp();
 | 
			
		||||
    long getTimestamp();
 | 
			
		||||
    
 | 
			
		||||
    // optional bytes message = 5;
 | 
			
		||||
    // optional bytes message = 6;
 | 
			
		||||
    boolean hasMessage();
 | 
			
		||||
    com.google.protobuf.ByteString getMessage();
 | 
			
		||||
  }
 | 
			
		||||
@@ -103,8 +107,40 @@ public final class PushMessageProtos {
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // repeated string destinations = 3;
 | 
			
		||||
    public static final int DESTINATIONS_FIELD_NUMBER = 3;
 | 
			
		||||
    // optional string relay = 3;
 | 
			
		||||
    public static final int RELAY_FIELD_NUMBER = 3;
 | 
			
		||||
    private java.lang.Object relay_;
 | 
			
		||||
    public boolean hasRelay() {
 | 
			
		||||
      return ((bitField0_ & 0x00000004) == 0x00000004);
 | 
			
		||||
    }
 | 
			
		||||
    public String getRelay() {
 | 
			
		||||
      java.lang.Object ref = relay_;
 | 
			
		||||
      if (ref instanceof String) {
 | 
			
		||||
        return (String) ref;
 | 
			
		||||
      } else {
 | 
			
		||||
        com.google.protobuf.ByteString bs = 
 | 
			
		||||
            (com.google.protobuf.ByteString) ref;
 | 
			
		||||
        String s = bs.toStringUtf8();
 | 
			
		||||
        if (com.google.protobuf.Internal.isValidUtf8(bs)) {
 | 
			
		||||
          relay_ = s;
 | 
			
		||||
        }
 | 
			
		||||
        return s;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    private com.google.protobuf.ByteString getRelayBytes() {
 | 
			
		||||
      java.lang.Object ref = relay_;
 | 
			
		||||
      if (ref instanceof String) {
 | 
			
		||||
        com.google.protobuf.ByteString b = 
 | 
			
		||||
            com.google.protobuf.ByteString.copyFromUtf8((String) ref);
 | 
			
		||||
        relay_ = b;
 | 
			
		||||
        return b;
 | 
			
		||||
      } else {
 | 
			
		||||
        return (com.google.protobuf.ByteString) ref;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // repeated string destinations = 4;
 | 
			
		||||
    public static final int DESTINATIONS_FIELD_NUMBER = 4;
 | 
			
		||||
    private com.google.protobuf.LazyStringList destinations_;
 | 
			
		||||
    public java.util.List<String>
 | 
			
		||||
        getDestinationsList() {
 | 
			
		||||
@@ -117,21 +153,21 @@ public final class PushMessageProtos {
 | 
			
		||||
      return destinations_.get(index);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // optional uint64 timestamp = 4;
 | 
			
		||||
    public static final int TIMESTAMP_FIELD_NUMBER = 4;
 | 
			
		||||
    // optional uint64 timestamp = 5;
 | 
			
		||||
    public static final int TIMESTAMP_FIELD_NUMBER = 5;
 | 
			
		||||
    private long timestamp_;
 | 
			
		||||
    public boolean hasTimestamp() {
 | 
			
		||||
      return ((bitField0_ & 0x00000004) == 0x00000004);
 | 
			
		||||
      return ((bitField0_ & 0x00000008) == 0x00000008);
 | 
			
		||||
    }
 | 
			
		||||
    public long getTimestamp() {
 | 
			
		||||
      return timestamp_;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // optional bytes message = 5;
 | 
			
		||||
    public static final int MESSAGE_FIELD_NUMBER = 5;
 | 
			
		||||
    // optional bytes message = 6;
 | 
			
		||||
    public static final int MESSAGE_FIELD_NUMBER = 6;
 | 
			
		||||
    private com.google.protobuf.ByteString message_;
 | 
			
		||||
    public boolean hasMessage() {
 | 
			
		||||
      return ((bitField0_ & 0x00000008) == 0x00000008);
 | 
			
		||||
      return ((bitField0_ & 0x00000010) == 0x00000010);
 | 
			
		||||
    }
 | 
			
		||||
    public com.google.protobuf.ByteString getMessage() {
 | 
			
		||||
      return message_;
 | 
			
		||||
@@ -140,6 +176,7 @@ public final class PushMessageProtos {
 | 
			
		||||
    private void initFields() {
 | 
			
		||||
      type_ = 0;
 | 
			
		||||
      source_ = "";
 | 
			
		||||
      relay_ = "";
 | 
			
		||||
      destinations_ = com.google.protobuf.LazyStringArrayList.EMPTY;
 | 
			
		||||
      timestamp_ = 0L;
 | 
			
		||||
      message_ = com.google.protobuf.ByteString.EMPTY;
 | 
			
		||||
@@ -162,14 +199,17 @@ public final class PushMessageProtos {
 | 
			
		||||
      if (((bitField0_ & 0x00000002) == 0x00000002)) {
 | 
			
		||||
        output.writeBytes(2, getSourceBytes());
 | 
			
		||||
      }
 | 
			
		||||
      for (int i = 0; i < destinations_.size(); i++) {
 | 
			
		||||
        output.writeBytes(3, destinations_.getByteString(i));
 | 
			
		||||
      }
 | 
			
		||||
      if (((bitField0_ & 0x00000004) == 0x00000004)) {
 | 
			
		||||
        output.writeUInt64(4, timestamp_);
 | 
			
		||||
        output.writeBytes(3, getRelayBytes());
 | 
			
		||||
      }
 | 
			
		||||
      for (int i = 0; i < destinations_.size(); i++) {
 | 
			
		||||
        output.writeBytes(4, destinations_.getByteString(i));
 | 
			
		||||
      }
 | 
			
		||||
      if (((bitField0_ & 0x00000008) == 0x00000008)) {
 | 
			
		||||
        output.writeBytes(5, message_);
 | 
			
		||||
        output.writeUInt64(5, timestamp_);
 | 
			
		||||
      }
 | 
			
		||||
      if (((bitField0_ & 0x00000010) == 0x00000010)) {
 | 
			
		||||
        output.writeBytes(6, message_);
 | 
			
		||||
      }
 | 
			
		||||
      getUnknownFields().writeTo(output);
 | 
			
		||||
    }
 | 
			
		||||
@@ -188,6 +228,10 @@ public final class PushMessageProtos {
 | 
			
		||||
        size += com.google.protobuf.CodedOutputStream
 | 
			
		||||
          .computeBytesSize(2, getSourceBytes());
 | 
			
		||||
      }
 | 
			
		||||
      if (((bitField0_ & 0x00000004) == 0x00000004)) {
 | 
			
		||||
        size += com.google.protobuf.CodedOutputStream
 | 
			
		||||
          .computeBytesSize(3, getRelayBytes());
 | 
			
		||||
      }
 | 
			
		||||
      {
 | 
			
		||||
        int dataSize = 0;
 | 
			
		||||
        for (int i = 0; i < destinations_.size(); i++) {
 | 
			
		||||
@@ -197,13 +241,13 @@ public final class PushMessageProtos {
 | 
			
		||||
        size += dataSize;
 | 
			
		||||
        size += 1 * getDestinationsList().size();
 | 
			
		||||
      }
 | 
			
		||||
      if (((bitField0_ & 0x00000004) == 0x00000004)) {
 | 
			
		||||
        size += com.google.protobuf.CodedOutputStream
 | 
			
		||||
          .computeUInt64Size(4, timestamp_);
 | 
			
		||||
      }
 | 
			
		||||
      if (((bitField0_ & 0x00000008) == 0x00000008)) {
 | 
			
		||||
        size += com.google.protobuf.CodedOutputStream
 | 
			
		||||
          .computeBytesSize(5, message_);
 | 
			
		||||
          .computeUInt64Size(5, timestamp_);
 | 
			
		||||
      }
 | 
			
		||||
      if (((bitField0_ & 0x00000010) == 0x00000010)) {
 | 
			
		||||
        size += com.google.protobuf.CodedOutputStream
 | 
			
		||||
          .computeBytesSize(6, message_);
 | 
			
		||||
      }
 | 
			
		||||
      size += getUnknownFields().getSerializedSize();
 | 
			
		||||
      memoizedSerializedSize = size;
 | 
			
		||||
@@ -333,12 +377,14 @@ public final class PushMessageProtos {
 | 
			
		||||
        bitField0_ = (bitField0_ & ~0x00000001);
 | 
			
		||||
        source_ = "";
 | 
			
		||||
        bitField0_ = (bitField0_ & ~0x00000002);
 | 
			
		||||
        destinations_ = com.google.protobuf.LazyStringArrayList.EMPTY;
 | 
			
		||||
        relay_ = "";
 | 
			
		||||
        bitField0_ = (bitField0_ & ~0x00000004);
 | 
			
		||||
        timestamp_ = 0L;
 | 
			
		||||
        destinations_ = com.google.protobuf.LazyStringArrayList.EMPTY;
 | 
			
		||||
        bitField0_ = (bitField0_ & ~0x00000008);
 | 
			
		||||
        message_ = com.google.protobuf.ByteString.EMPTY;
 | 
			
		||||
        timestamp_ = 0L;
 | 
			
		||||
        bitField0_ = (bitField0_ & ~0x00000010);
 | 
			
		||||
        message_ = com.google.protobuf.ByteString.EMPTY;
 | 
			
		||||
        bitField0_ = (bitField0_ & ~0x00000020);
 | 
			
		||||
        return this;
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
@@ -385,19 +431,23 @@ public final class PushMessageProtos {
 | 
			
		||||
          to_bitField0_ |= 0x00000002;
 | 
			
		||||
        }
 | 
			
		||||
        result.source_ = source_;
 | 
			
		||||
        if (((bitField0_ & 0x00000004) == 0x00000004)) {
 | 
			
		||||
          destinations_ = new com.google.protobuf.UnmodifiableLazyStringList(
 | 
			
		||||
              destinations_);
 | 
			
		||||
          bitField0_ = (bitField0_ & ~0x00000004);
 | 
			
		||||
        }
 | 
			
		||||
        result.destinations_ = destinations_;
 | 
			
		||||
        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
 | 
			
		||||
        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
 | 
			
		||||
          to_bitField0_ |= 0x00000004;
 | 
			
		||||
        }
 | 
			
		||||
        result.timestamp_ = timestamp_;
 | 
			
		||||
        result.relay_ = relay_;
 | 
			
		||||
        if (((bitField0_ & 0x00000008) == 0x00000008)) {
 | 
			
		||||
          destinations_ = new com.google.protobuf.UnmodifiableLazyStringList(
 | 
			
		||||
              destinations_);
 | 
			
		||||
          bitField0_ = (bitField0_ & ~0x00000008);
 | 
			
		||||
        }
 | 
			
		||||
        result.destinations_ = destinations_;
 | 
			
		||||
        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
 | 
			
		||||
          to_bitField0_ |= 0x00000008;
 | 
			
		||||
        }
 | 
			
		||||
        result.timestamp_ = timestamp_;
 | 
			
		||||
        if (((from_bitField0_ & 0x00000020) == 0x00000020)) {
 | 
			
		||||
          to_bitField0_ |= 0x00000010;
 | 
			
		||||
        }
 | 
			
		||||
        result.message_ = message_;
 | 
			
		||||
        result.bitField0_ = to_bitField0_;
 | 
			
		||||
        onBuilt();
 | 
			
		||||
@@ -421,10 +471,13 @@ public final class PushMessageProtos {
 | 
			
		||||
        if (other.hasSource()) {
 | 
			
		||||
          setSource(other.getSource());
 | 
			
		||||
        }
 | 
			
		||||
        if (other.hasRelay()) {
 | 
			
		||||
          setRelay(other.getRelay());
 | 
			
		||||
        }
 | 
			
		||||
        if (!other.destinations_.isEmpty()) {
 | 
			
		||||
          if (destinations_.isEmpty()) {
 | 
			
		||||
            destinations_ = other.destinations_;
 | 
			
		||||
            bitField0_ = (bitField0_ & ~0x00000004);
 | 
			
		||||
            bitField0_ = (bitField0_ & ~0x00000008);
 | 
			
		||||
          } else {
 | 
			
		||||
            ensureDestinationsIsMutable();
 | 
			
		||||
            destinations_.addAll(other.destinations_);
 | 
			
		||||
@@ -479,17 +532,22 @@ public final class PushMessageProtos {
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
            case 26: {
 | 
			
		||||
              bitField0_ |= 0x00000004;
 | 
			
		||||
              relay_ = input.readBytes();
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
            case 34: {
 | 
			
		||||
              ensureDestinationsIsMutable();
 | 
			
		||||
              destinations_.add(input.readBytes());
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
            case 32: {
 | 
			
		||||
              bitField0_ |= 0x00000008;
 | 
			
		||||
            case 40: {
 | 
			
		||||
              bitField0_ |= 0x00000010;
 | 
			
		||||
              timestamp_ = input.readUInt64();
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
            case 42: {
 | 
			
		||||
              bitField0_ |= 0x00000010;
 | 
			
		||||
            case 50: {
 | 
			
		||||
              bitField0_ |= 0x00000020;
 | 
			
		||||
              message_ = input.readBytes();
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
@@ -556,12 +614,48 @@ public final class PushMessageProtos {
 | 
			
		||||
        onChanged();
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      // repeated string destinations = 3;
 | 
			
		||||
      // optional string relay = 3;
 | 
			
		||||
      private java.lang.Object relay_ = "";
 | 
			
		||||
      public boolean hasRelay() {
 | 
			
		||||
        return ((bitField0_ & 0x00000004) == 0x00000004);
 | 
			
		||||
      }
 | 
			
		||||
      public String getRelay() {
 | 
			
		||||
        java.lang.Object ref = relay_;
 | 
			
		||||
        if (!(ref instanceof String)) {
 | 
			
		||||
          String s = ((com.google.protobuf.ByteString) ref).toStringUtf8();
 | 
			
		||||
          relay_ = s;
 | 
			
		||||
          return s;
 | 
			
		||||
        } else {
 | 
			
		||||
          return (String) ref;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      public Builder setRelay(String value) {
 | 
			
		||||
        if (value == null) {
 | 
			
		||||
    throw new NullPointerException();
 | 
			
		||||
  }
 | 
			
		||||
  bitField0_ |= 0x00000004;
 | 
			
		||||
        relay_ = value;
 | 
			
		||||
        onChanged();
 | 
			
		||||
        return this;
 | 
			
		||||
      }
 | 
			
		||||
      public Builder clearRelay() {
 | 
			
		||||
        bitField0_ = (bitField0_ & ~0x00000004);
 | 
			
		||||
        relay_ = getDefaultInstance().getRelay();
 | 
			
		||||
        onChanged();
 | 
			
		||||
        return this;
 | 
			
		||||
      }
 | 
			
		||||
      void setRelay(com.google.protobuf.ByteString value) {
 | 
			
		||||
        bitField0_ |= 0x00000004;
 | 
			
		||||
        relay_ = value;
 | 
			
		||||
        onChanged();
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      // repeated string destinations = 4;
 | 
			
		||||
      private com.google.protobuf.LazyStringList destinations_ = com.google.protobuf.LazyStringArrayList.EMPTY;
 | 
			
		||||
      private void ensureDestinationsIsMutable() {
 | 
			
		||||
        if (!((bitField0_ & 0x00000004) == 0x00000004)) {
 | 
			
		||||
        if (!((bitField0_ & 0x00000008) == 0x00000008)) {
 | 
			
		||||
          destinations_ = new com.google.protobuf.LazyStringArrayList(destinations_);
 | 
			
		||||
          bitField0_ |= 0x00000004;
 | 
			
		||||
          bitField0_ |= 0x00000008;
 | 
			
		||||
         }
 | 
			
		||||
      }
 | 
			
		||||
      public java.util.List<String>
 | 
			
		||||
@@ -602,7 +696,7 @@ public final class PushMessageProtos {
 | 
			
		||||
      }
 | 
			
		||||
      public Builder clearDestinations() {
 | 
			
		||||
        destinations_ = com.google.protobuf.LazyStringArrayList.EMPTY;
 | 
			
		||||
        bitField0_ = (bitField0_ & ~0x00000004);
 | 
			
		||||
        bitField0_ = (bitField0_ & ~0x00000008);
 | 
			
		||||
        onChanged();
 | 
			
		||||
        return this;
 | 
			
		||||
      }
 | 
			
		||||
@@ -612,31 +706,31 @@ public final class PushMessageProtos {
 | 
			
		||||
        onChanged();
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      // optional uint64 timestamp = 4;
 | 
			
		||||
      // optional uint64 timestamp = 5;
 | 
			
		||||
      private long timestamp_ ;
 | 
			
		||||
      public boolean hasTimestamp() {
 | 
			
		||||
        return ((bitField0_ & 0x00000008) == 0x00000008);
 | 
			
		||||
        return ((bitField0_ & 0x00000010) == 0x00000010);
 | 
			
		||||
      }
 | 
			
		||||
      public long getTimestamp() {
 | 
			
		||||
        return timestamp_;
 | 
			
		||||
      }
 | 
			
		||||
      public Builder setTimestamp(long value) {
 | 
			
		||||
        bitField0_ |= 0x00000008;
 | 
			
		||||
        bitField0_ |= 0x00000010;
 | 
			
		||||
        timestamp_ = value;
 | 
			
		||||
        onChanged();
 | 
			
		||||
        return this;
 | 
			
		||||
      }
 | 
			
		||||
      public Builder clearTimestamp() {
 | 
			
		||||
        bitField0_ = (bitField0_ & ~0x00000008);
 | 
			
		||||
        bitField0_ = (bitField0_ & ~0x00000010);
 | 
			
		||||
        timestamp_ = 0L;
 | 
			
		||||
        onChanged();
 | 
			
		||||
        return this;
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      // optional bytes message = 5;
 | 
			
		||||
      // optional bytes message = 6;
 | 
			
		||||
      private com.google.protobuf.ByteString message_ = com.google.protobuf.ByteString.EMPTY;
 | 
			
		||||
      public boolean hasMessage() {
 | 
			
		||||
        return ((bitField0_ & 0x00000010) == 0x00000010);
 | 
			
		||||
        return ((bitField0_ & 0x00000020) == 0x00000020);
 | 
			
		||||
      }
 | 
			
		||||
      public com.google.protobuf.ByteString getMessage() {
 | 
			
		||||
        return message_;
 | 
			
		||||
@@ -645,13 +739,13 @@ public final class PushMessageProtos {
 | 
			
		||||
        if (value == null) {
 | 
			
		||||
    throw new NullPointerException();
 | 
			
		||||
  }
 | 
			
		||||
  bitField0_ |= 0x00000010;
 | 
			
		||||
  bitField0_ |= 0x00000020;
 | 
			
		||||
        message_ = value;
 | 
			
		||||
        onChanged();
 | 
			
		||||
        return this;
 | 
			
		||||
      }
 | 
			
		||||
      public Builder clearMessage() {
 | 
			
		||||
        bitField0_ = (bitField0_ & ~0x00000010);
 | 
			
		||||
        bitField0_ = (bitField0_ & ~0x00000020);
 | 
			
		||||
        message_ = getDefaultInstance().getMessage();
 | 
			
		||||
        onChanged();
 | 
			
		||||
        return this;
 | 
			
		||||
@@ -1833,15 +1927,16 @@ public final class PushMessageProtos {
 | 
			
		||||
  static {
 | 
			
		||||
    java.lang.String[] descriptorData = {
 | 
			
		||||
      "\n\037IncomingPushMessageSignal.proto\022\ntexts" +
 | 
			
		||||
      "ecure\"s\n\031IncomingPushMessageSignal\022\014\n\004ty" +
 | 
			
		||||
      "pe\030\001 \001(\r\022\016\n\006source\030\002 \001(\t\022\024\n\014destinations" +
 | 
			
		||||
      "\030\003 \003(\t\022\021\n\ttimestamp\030\004 \001(\004\022\017\n\007message\030\005 \001" +
 | 
			
		||||
      "(\014\"\254\001\n\022PushMessageContent\022\014\n\004body\030\001 \001(\t\022" +
 | 
			
		||||
      "E\n\013attachments\030\002 \003(\01320.textsecure.PushMe" +
 | 
			
		||||
      "ssageContent.AttachmentPointer\032A\n\021Attach" +
 | 
			
		||||
      "mentPointer\022\n\n\002id\030\001 \001(\006\022\023\n\013contentType\030\002" +
 | 
			
		||||
      " \001(\t\022\013\n\003key\030\003 \001(\014B7\n\"org.whispersystems." +
 | 
			
		||||
      "textsecure.pushB\021PushMessageProtos"
 | 
			
		||||
      "ecure\"\202\001\n\031IncomingPushMessageSignal\022\014\n\004t" +
 | 
			
		||||
      "ype\030\001 \001(\r\022\016\n\006source\030\002 \001(\t\022\r\n\005relay\030\003 \001(\t" +
 | 
			
		||||
      "\022\024\n\014destinations\030\004 \003(\t\022\021\n\ttimestamp\030\005 \001(" +
 | 
			
		||||
      "\004\022\017\n\007message\030\006 \001(\014\"\254\001\n\022PushMessageConten" +
 | 
			
		||||
      "t\022\014\n\004body\030\001 \001(\t\022E\n\013attachments\030\002 \003(\01320.t" +
 | 
			
		||||
      "extsecure.PushMessageContent.AttachmentP" +
 | 
			
		||||
      "ointer\032A\n\021AttachmentPointer\022\n\n\002id\030\001 \001(\006\022" +
 | 
			
		||||
      "\023\n\013contentType\030\002 \001(\t\022\013\n\003key\030\003 \001(\014B7\n\"org" +
 | 
			
		||||
      ".whispersystems.textsecure.pushB\021PushMes",
 | 
			
		||||
      "sageProtos"
 | 
			
		||||
    };
 | 
			
		||||
    com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
 | 
			
		||||
      new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
 | 
			
		||||
@@ -1853,7 +1948,7 @@ public final class PushMessageProtos {
 | 
			
		||||
          internal_static_textsecure_IncomingPushMessageSignal_fieldAccessorTable = new
 | 
			
		||||
            com.google.protobuf.GeneratedMessage.FieldAccessorTable(
 | 
			
		||||
              internal_static_textsecure_IncomingPushMessageSignal_descriptor,
 | 
			
		||||
              new java.lang.String[] { "Type", "Source", "Destinations", "Timestamp", "Message", },
 | 
			
		||||
              new java.lang.String[] { "Type", "Source", "Relay", "Destinations", "Timestamp", "Message", },
 | 
			
		||||
              org.whispersystems.textsecure.push.PushMessageProtos.IncomingPushMessageSignal.class,
 | 
			
		||||
              org.whispersystems.textsecure.push.PushMessageProtos.IncomingPushMessageSignal.Builder.class);
 | 
			
		||||
          internal_static_textsecure_PushMessageContent_descriptor =
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import android.util.Log;
 | 
			
		||||
import android.util.Pair;
 | 
			
		||||
 | 
			
		||||
import com.google.thoughtcrimegson.Gson;
 | 
			
		||||
 | 
			
		||||
import org.whispersystems.textsecure.R;
 | 
			
		||||
import org.whispersystems.textsecure.Release;
 | 
			
		||||
import org.whispersystems.textsecure.crypto.IdentityKey;
 | 
			
		||||
@@ -12,9 +13,6 @@ import org.whispersystems.textsecure.storage.PreKeyRecord;
 | 
			
		||||
import org.whispersystems.textsecure.util.Base64;
 | 
			
		||||
import org.whispersystems.textsecure.util.Util;
 | 
			
		||||
 | 
			
		||||
import javax.net.ssl.HttpsURLConnection;
 | 
			
		||||
import javax.net.ssl.SSLContext;
 | 
			
		||||
import javax.net.ssl.TrustManagerFactory;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileOutputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
@@ -34,6 +32,10 @@ import java.util.LinkedList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import javax.net.ssl.HttpsURLConnection;
 | 
			
		||||
import javax.net.ssl.SSLContext;
 | 
			
		||||
import javax.net.ssl.TrustManagerFactory;
 | 
			
		||||
 | 
			
		||||
public class PushServiceSocket {
 | 
			
		||||
 | 
			
		||||
  private static final String CREATE_ACCOUNT_SMS_PATH   = "/v1/accounts/sms/code/%s";
 | 
			
		||||
@@ -78,28 +80,31 @@ public class PushServiceSocket {
 | 
			
		||||
    makeRequest(REGISTER_GCM_PATH, "DELETE", null);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void sendMessage(String recipient, byte[] body, int type)
 | 
			
		||||
  public void sendMessage(String relay, String recipient, byte[] body, int type)
 | 
			
		||||
      throws IOException
 | 
			
		||||
  {
 | 
			
		||||
    OutgoingPushMessage message = new OutgoingPushMessage(recipient, body, type);
 | 
			
		||||
    OutgoingPushMessage message = new OutgoingPushMessage(relay, recipient, body, type);
 | 
			
		||||
    sendMessage(new OutgoingPushMessageList(message));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void sendMessage(List<String> recipients, List<byte[]> bodies, List<Integer> types)
 | 
			
		||||
  public void sendMessage(List<String> relays, List<String> recipients,
 | 
			
		||||
                          List<byte[]> bodies, List<Integer> types)
 | 
			
		||||
      throws IOException
 | 
			
		||||
  {
 | 
			
		||||
    List<OutgoingPushMessage> messages = new LinkedList<OutgoingPushMessage>();
 | 
			
		||||
 | 
			
		||||
    Iterator<String>  relaysIterator     = relays.iterator();
 | 
			
		||||
    Iterator<String>  recipientsIterator = recipients.iterator();
 | 
			
		||||
    Iterator<byte[]>  bodiesIterator     = bodies.iterator();
 | 
			
		||||
    Iterator<Integer> typesIterator      = types.iterator();
 | 
			
		||||
 | 
			
		||||
    while (recipientsIterator.hasNext()) {
 | 
			
		||||
      String relay     = relaysIterator.next();
 | 
			
		||||
      String recipient = recipientsIterator.next();
 | 
			
		||||
      byte[] body      = bodiesIterator.next();
 | 
			
		||||
      int    type      = typesIterator.next();
 | 
			
		||||
 | 
			
		||||
      messages.add(new OutgoingPushMessage(recipient, body, type));
 | 
			
		||||
      messages.add(new OutgoingPushMessage(relay, recipient, body, type));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sendMessage(new OutgoingPushMessageList(messages));
 | 
			
		||||
@@ -134,8 +139,14 @@ public class PushServiceSocket {
 | 
			
		||||
     makeRequest(String.format(PREKEY_PATH, ""), "PUT", PreKeyList.toJson(new PreKeyList(lastResortEntity, entities)));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public PreKeyEntity getPreKey(String number) throws IOException {
 | 
			
		||||
    String responseText = makeRequest(String.format(PREKEY_PATH, number), "GET", null);
 | 
			
		||||
  public PreKeyEntity getPreKey(String number, String relay) throws IOException {
 | 
			
		||||
    String path = String.format(PREKEY_PATH, number);
 | 
			
		||||
 | 
			
		||||
    if (relay != null) {
 | 
			
		||||
      path = path + "?relay=" + relay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    String responseText = makeRequest(path, "GET", null);
 | 
			
		||||
    Log.w("PushServiceSocket", "Got prekey: " + responseText);
 | 
			
		||||
    return PreKeyEntity.fromJson(responseText);
 | 
			
		||||
  }
 | 
			
		||||
@@ -170,11 +181,11 @@ public class PushServiceSocket {
 | 
			
		||||
    return attachment;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public List<String> retrieveDirectory(Set<String> contactTokens) {
 | 
			
		||||
  public List<ContactTokenDetails> retrieveDirectory(Set<String> contactTokens) {
 | 
			
		||||
    try {
 | 
			
		||||
      ContactTokenList contactTokenList = new ContactTokenList(new LinkedList(contactTokens));
 | 
			
		||||
      String           response         = makeRequest(DIRECTORY_TOKENS_PATH, "PUT", new Gson().toJson(contactTokenList));
 | 
			
		||||
      ContactTokenList activeTokens     = new Gson().fromJson(response, ContactTokenList.class);
 | 
			
		||||
      ContactTokenList        contactTokenList = new ContactTokenList(new LinkedList(contactTokens));
 | 
			
		||||
      String                  response         = makeRequest(DIRECTORY_TOKENS_PATH, "PUT", new Gson().toJson(contactTokenList));
 | 
			
		||||
      ContactTokenDetailsList activeTokens     = new Gson().fromJson(response, ContactTokenDetailsList.class);
 | 
			
		||||
 | 
			
		||||
      return activeTokens.getContacts();
 | 
			
		||||
    } catch (IOException ioe) {
 | 
			
		||||
@@ -183,12 +194,12 @@ public class PushServiceSocket {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public boolean isRegisteredUser(String contactToken) throws IOException {
 | 
			
		||||
  public ContactTokenDetails getContactTokenDetails(String contactToken) throws IOException {
 | 
			
		||||
    try {
 | 
			
		||||
      makeRequest(String.format(DIRECTORY_VERIFY_PATH, contactToken), "GET", null);
 | 
			
		||||
      return true;
 | 
			
		||||
      String response = makeRequest(String.format(DIRECTORY_VERIFY_PATH, contactToken), "GET", null);
 | 
			
		||||
      return new Gson().fromJson(response, ContactTokenDetails.class);
 | 
			
		||||
    } catch (NotFoundException nfe) {
 | 
			
		||||
      return false;
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -311,6 +322,9 @@ public class PushServiceSocket {
 | 
			
		||||
      context.init(null, trustManagerFactory.getTrustManagers(), null);
 | 
			
		||||
 | 
			
		||||
      URL url = new URL(String.format("%s%s", Release.PUSH_SERVICE_URL, urlFragment));
 | 
			
		||||
      Log.w("PushServiceSocket", "Push service URL: " + Release.PUSH_SERVICE_URL);
 | 
			
		||||
      Log.w("PushServiceSocket", "Opening URL: " + url);
 | 
			
		||||
 | 
			
		||||
      HttpURLConnection connection = (HttpURLConnection)url.openConnection();
 | 
			
		||||
 | 
			
		||||
      if (Release.ENFORCE_SSL) {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,8 @@ import org.thoughtcrime.securesms.service.SendReceiveService;
 | 
			
		||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
 | 
			
		||||
import org.whispersystems.textsecure.crypto.InvalidVersionException;
 | 
			
		||||
import org.whispersystems.textsecure.directory.Directory;
 | 
			
		||||
import org.whispersystems.textsecure.directory.NotInDirectoryException;
 | 
			
		||||
import org.whispersystems.textsecure.push.ContactTokenDetails;
 | 
			
		||||
import org.whispersystems.textsecure.push.IncomingEncryptedPushMessage;
 | 
			
		||||
import org.whispersystems.textsecure.push.IncomingPushMessage;
 | 
			
		||||
import org.whispersystems.textsecure.push.PushServiceSocket;
 | 
			
		||||
@@ -59,13 +61,16 @@ public class GcmIntentService extends GCMBaseIntentService {
 | 
			
		||||
      IncomingEncryptedPushMessage encryptedMessage = new IncomingEncryptedPushMessage(data, sessionKey);
 | 
			
		||||
      IncomingPushMessage          message          = encryptedMessage.getIncomingPushMessage();
 | 
			
		||||
 | 
			
		||||
      if (!isActiveNumber(context, message.getSource())) {
 | 
			
		||||
        Directory           directory           = Directory.getInstance(context);
 | 
			
		||||
        String              contactToken        = directory.getToken(message.getSource());
 | 
			
		||||
        ContactTokenDetails contactTokenDetails = new ContactTokenDetails(contactToken, message.getRelay());
 | 
			
		||||
        directory.setToken(contactTokenDetails, true);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      Intent service = new Intent(context, SendReceiveService.class);
 | 
			
		||||
      service.setAction(SendReceiveService.RECEIVE_PUSH_ACTION);
 | 
			
		||||
      service.putExtra("message", message);
 | 
			
		||||
 | 
			
		||||
      Directory directory = Directory.getInstance(context);
 | 
			
		||||
      directory.setToken(directory.getToken(message.getSource()), true);
 | 
			
		||||
 | 
			
		||||
      context.startService(service);
 | 
			
		||||
    } catch (IOException e) {
 | 
			
		||||
      Log.w("GcmIntentService", e);
 | 
			
		||||
@@ -84,4 +89,16 @@ public class GcmIntentService extends GCMBaseIntentService {
 | 
			
		||||
    String password    = TextSecurePreferences.getPushServerPassword(context);
 | 
			
		||||
    return new PushServiceSocket(context, localNumber, password);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private boolean isActiveNumber(Context context, String e164number) {
 | 
			
		||||
    boolean isActiveNumber;
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      isActiveNumber = Directory.getInstance(context).isActiveNumber(e164number);
 | 
			
		||||
    } catch (NotInDirectoryException e) {
 | 
			
		||||
      isActiveNumber = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return isActiveNumber;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ import android.util.Log;
 | 
			
		||||
 | 
			
		||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
 | 
			
		||||
import org.whispersystems.textsecure.directory.Directory;
 | 
			
		||||
import org.whispersystems.textsecure.push.ContactTokenDetails;
 | 
			
		||||
import org.whispersystems.textsecure.push.PushServiceSocket;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -61,11 +62,14 @@ public class DirectoryRefreshService extends Service {
 | 
			
		||||
        String            password    = TextSecurePreferences.getPushServerPassword(context);
 | 
			
		||||
        PushServiceSocket socket      = new PushServiceSocket(context, localNumber, password);
 | 
			
		||||
 | 
			
		||||
        Set<String>  eligibleContactTokens = directory.getPushEligibleContactTokens(localNumber);
 | 
			
		||||
        List<String> activeTokens          = socket.retrieveDirectory(eligibleContactTokens);
 | 
			
		||||
        Set<String> eligibleContactTokens = directory.getPushEligibleContactTokens(localNumber);
 | 
			
		||||
        List<ContactTokenDetails> activeTokens  = socket.retrieveDirectory(eligibleContactTokens);
 | 
			
		||||
 | 
			
		||||
        if (activeTokens != null) {
 | 
			
		||||
          eligibleContactTokens.removeAll(activeTokens);
 | 
			
		||||
          for (ContactTokenDetails activeToken : activeTokens) {
 | 
			
		||||
            eligibleContactTokens.remove(activeToken.getToken());
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          directory.setTokens(activeTokens, eligibleContactTokens);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@ import org.whispersystems.textsecure.crypto.IdentityKey;
 | 
			
		||||
import org.whispersystems.textsecure.crypto.MasterSecret;
 | 
			
		||||
import org.whispersystems.textsecure.crypto.PreKeyUtil;
 | 
			
		||||
import org.whispersystems.textsecure.directory.Directory;
 | 
			
		||||
import org.whispersystems.textsecure.push.ContactTokenDetails;
 | 
			
		||||
import org.whispersystems.textsecure.push.PushServiceSocket;
 | 
			
		||||
import org.whispersystems.textsecure.storage.PreKeyRecord;
 | 
			
		||||
import org.whispersystems.textsecure.util.Util;
 | 
			
		||||
@@ -282,11 +283,13 @@ public class RegistrationService extends Service {
 | 
			
		||||
    String gcmRegistrationId = waitForGcmRegistrationId();
 | 
			
		||||
    socket.registerGcmId(gcmRegistrationId);
 | 
			
		||||
 | 
			
		||||
    Set<String> contactTokens = Directory.getInstance(this).getPushEligibleContactTokens(number);
 | 
			
		||||
    List<String> activeTokens = socket.retrieveDirectory(contactTokens);
 | 
			
		||||
    Set<String>               contactTokens = Directory.getInstance(this).getPushEligibleContactTokens(number);
 | 
			
		||||
    List<ContactTokenDetails> activeTokens  = socket.retrieveDirectory(contactTokens);
 | 
			
		||||
 | 
			
		||||
    if (activeTokens != null) {
 | 
			
		||||
      contactTokens.removeAll(activeTokens);
 | 
			
		||||
      for (ContactTokenDetails activeToken : activeTokens) {
 | 
			
		||||
        contactTokens.remove(activeToken.getToken());
 | 
			
		||||
      }
 | 
			
		||||
      Directory.getInstance(this).setTokens(activeTokens, contactTokens);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,7 @@ import org.whispersystems.textsecure.crypto.KeyUtil;
 | 
			
		||||
import org.whispersystems.textsecure.crypto.MasterSecret;
 | 
			
		||||
import org.whispersystems.textsecure.crypto.MessageCipher;
 | 
			
		||||
import org.whispersystems.textsecure.crypto.protocol.PreKeyBundleMessage;
 | 
			
		||||
import org.whispersystems.textsecure.directory.Directory;
 | 
			
		||||
import org.whispersystems.textsecure.push.OutgoingPushMessage;
 | 
			
		||||
import org.whispersystems.textsecure.push.PreKeyEntity;
 | 
			
		||||
import org.whispersystems.textsecure.push.PushAttachmentData;
 | 
			
		||||
@@ -61,12 +62,12 @@ public class PushTransport extends BaseTransport {
 | 
			
		||||
      String                     plaintextBody            = message.getBody().getBody();
 | 
			
		||||
      PushMessageContent.Builder builder                  = PushMessageContent.newBuilder();
 | 
			
		||||
      byte[]                     plaintext                = builder.setBody(plaintextBody).build().toByteArray();
 | 
			
		||||
      String                     recipientCanonicalNumber = PhoneNumberFormatter.formatNumber(recipient.getNumber(),
 | 
			
		||||
                                                                                              localNumber);
 | 
			
		||||
      String                     recipientCanonicalNumber = PhoneNumberFormatter.formatNumber(recipient.getNumber(), localNumber);
 | 
			
		||||
      String                     relay                    = Directory.getInstance(context).getRelay(recipientCanonicalNumber);
 | 
			
		||||
 | 
			
		||||
      Pair<Integer, byte[]> typeAndCiphertext = getEncryptedMessage(socket, recipient, recipientCanonicalNumber, plaintext);
 | 
			
		||||
 | 
			
		||||
      socket.sendMessage(recipientCanonicalNumber, typeAndCiphertext.second, typeAndCiphertext.first);
 | 
			
		||||
      socket.sendMessage(relay, recipientCanonicalNumber, typeAndCiphertext.second, typeAndCiphertext.first);
 | 
			
		||||
 | 
			
		||||
      context.sendBroadcast(constructSentIntent(context, message.getId(), message.getType()));
 | 
			
		||||
    } catch (RateLimitException e) {
 | 
			
		||||
@@ -81,7 +82,8 @@ public class PushTransport extends BaseTransport {
 | 
			
		||||
      String            password    = TextSecurePreferences.getPushServerPassword(context);
 | 
			
		||||
      PushServiceSocket socket      = new PushServiceSocket(context, localNumber, password);
 | 
			
		||||
      String            messageBody = PartParser.getMessageText(message.getBody());
 | 
			
		||||
      List<byte[]>      ciphertext  = new LinkedList<byte[]> ();
 | 
			
		||||
      List<String>      relays      = new LinkedList<String>();
 | 
			
		||||
      List<byte[]>      ciphertext  = new LinkedList<byte[]>();
 | 
			
		||||
      List<Integer>     types       = new LinkedList<Integer>();
 | 
			
		||||
 | 
			
		||||
      for (String destination : destinations) {
 | 
			
		||||
@@ -108,11 +110,12 @@ public class PushTransport extends BaseTransport {
 | 
			
		||||
        Pair<Integer, byte[]> typeAndCiphertext = getEncryptedMessage(socket, recipients.getPrimaryRecipient(),
 | 
			
		||||
                                                                      destination, plaintext);
 | 
			
		||||
 | 
			
		||||
        relays.add(Directory.getInstance(context).getRelay(destination));
 | 
			
		||||
        types.add(typeAndCiphertext.first);
 | 
			
		||||
        ciphertext.add(typeAndCiphertext.second);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      socket.sendMessage(destinations, ciphertext, types);
 | 
			
		||||
      socket.sendMessage(relays, destinations, ciphertext, types);
 | 
			
		||||
 | 
			
		||||
    } catch (RateLimitException e) {
 | 
			
		||||
      Log.w("PushTransport", e);
 | 
			
		||||
@@ -187,7 +190,8 @@ public class PushTransport extends BaseTransport {
 | 
			
		||||
  {
 | 
			
		||||
    IdentityKeyPair      identityKeyPair = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret);
 | 
			
		||||
    IdentityKey          identityKey     = identityKeyPair.getPublicKey();
 | 
			
		||||
    PreKeyEntity         preKey          = socket.getPreKey(canonicalRecipientNumber);
 | 
			
		||||
    String               relay           = Directory.getInstance(context).getRelay(canonicalRecipientNumber);
 | 
			
		||||
    PreKeyEntity         preKey          = socket.getPreKey(canonicalRecipientNumber, relay);
 | 
			
		||||
    KeyExchangeProcessor processor       = new KeyExchangeProcessor(context, masterSecret, recipient);
 | 
			
		||||
 | 
			
		||||
    processor.processKeyExchangeMessage(preKey);
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,7 @@ import org.thoughtcrime.securesms.util.Util;
 | 
			
		||||
import org.whispersystems.textsecure.crypto.MasterSecret;
 | 
			
		||||
import org.whispersystems.textsecure.directory.Directory;
 | 
			
		||||
import org.whispersystems.textsecure.directory.NotInDirectoryException;
 | 
			
		||||
import org.whispersystems.textsecure.push.ContactTokenDetails;
 | 
			
		||||
import org.whispersystems.textsecure.push.PushServiceSocket;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
@@ -126,15 +127,20 @@ public class UniversalTransport {
 | 
			
		||||
      return directory.isActiveNumber(destination);
 | 
			
		||||
    } catch (NotInDirectoryException e) {
 | 
			
		||||
      try {
 | 
			
		||||
        String            localNumber    = TextSecurePreferences.getLocalNumber(context);
 | 
			
		||||
        String            pushPassword   = TextSecurePreferences.getPushServerPassword(context);
 | 
			
		||||
        String            contactToken   = directory.getToken(destination);
 | 
			
		||||
        PushServiceSocket socket         = new PushServiceSocket(context, localNumber, pushPassword);
 | 
			
		||||
        boolean           registeredUser = socket.isRegisteredUser(contactToken);
 | 
			
		||||
        String              localNumber    = TextSecurePreferences.getLocalNumber(context);
 | 
			
		||||
        String              pushPassword   = TextSecurePreferences.getPushServerPassword(context);
 | 
			
		||||
        String              contactToken   = directory.getToken(destination);
 | 
			
		||||
        PushServiceSocket   socket         = new PushServiceSocket(context, localNumber, pushPassword);
 | 
			
		||||
        ContactTokenDetails registeredUser = socket.getContactTokenDetails(contactToken);
 | 
			
		||||
 | 
			
		||||
        directory.setToken(contactToken, registeredUser);
 | 
			
		||||
 | 
			
		||||
        return registeredUser;
 | 
			
		||||
        if (registeredUser == null) {
 | 
			
		||||
          registeredUser = new ContactTokenDetails(contactToken);
 | 
			
		||||
          directory.setToken(registeredUser, false);
 | 
			
		||||
          return false;
 | 
			
		||||
        } else {
 | 
			
		||||
          directory.setToken(registeredUser, true);
 | 
			
		||||
          return true;
 | 
			
		||||
        }
 | 
			
		||||
      } catch (IOException e1) {
 | 
			
		||||
        Log.w("UniversalTransport", e1);
 | 
			
		||||
        return false;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user