Java Code Examples for org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer

The following examples show how to use org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer. These examples are extracted from open source projects. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
public SignalServiceAttachmentPointer uploadAttachment(SignalServiceAttachmentStream attachment) throws IOException {
  byte[]             attachmentKey    = attachment.getResumableUploadSpec().transform(ResumableUploadSpec::getSecretKey).or(() -> Util.getSecretBytes(64));
  byte[]             attachmentIV     = attachment.getResumableUploadSpec().transform(ResumableUploadSpec::getIV).or(() -> Util.getSecretBytes(16));
  long               paddedLength     = PaddingInputStream.getPaddedSize(attachment.getLength());
  InputStream        dataStream       = new PaddingInputStream(attachment.getInputStream(), attachment.getLength());
  long               ciphertextLength = AttachmentCipherOutputStream.getCiphertextLength(paddedLength);
  PushAttachmentData attachmentData   = new PushAttachmentData(attachment.getContentType(),
                                                               dataStream,
                                                               ciphertextLength,
                                                               new AttachmentCipherOutputStreamFactory(attachmentKey, attachmentIV),
                                                               attachment.getListener(),
                                                               attachment.getCancelationSignal(),
                                                               attachment.getResumableUploadSpec().orNull());

  if (attachmentsV3.get()) {
    return uploadAttachmentV3(attachment, attachmentKey, attachmentData);
  } else {
    return uploadAttachmentV2(attachment, attachmentKey, attachmentData);
  }
}
 
Example 2
private SignalServiceAttachmentPointer uploadAttachmentV3(SignalServiceAttachmentStream attachment, byte[] attachmentKey, PushAttachmentData attachmentData) throws IOException {
  byte[] digest = socket.uploadAttachment(attachmentData);
  return new SignalServiceAttachmentPointer(attachmentData.getResumableUploadSpec().getCdnNumber(),
                                            new SignalServiceAttachmentRemoteId(attachmentData.getResumableUploadSpec().getCdnKey()),
                                            attachment.getContentType(),
                                            attachmentKey,
                                            Optional.of(Util.toIntExact(attachment.getLength())),
                                            attachment.getPreview(),
                                            attachment.getWidth(),
                                            attachment.getHeight(),
                                            Optional.of(digest),
                                            attachment.getFileName(),
                                            attachment.getVoiceNote(),
                                            attachment.getCaption(),
                                            attachment.getBlurHash(),
                                            attachment.getUploadTimestamp());
}
 
Example 3
public void update(@NonNull GroupId.V1 groupId,
                   @Nullable String title,
                   @Nullable SignalServiceAttachmentPointer avatar)
{
  ContentValues contentValues = new ContentValues();
  if (title != null) contentValues.put(TITLE, title);

  if (avatar != null) {
    contentValues.put(AVATAR_ID, avatar.getRemoteId().getV2().get());
    contentValues.put(AVATAR_CONTENT_TYPE, avatar.getContentType());
    contentValues.put(AVATAR_KEY, avatar.getKey());
    contentValues.put(AVATAR_DIGEST, avatar.getDigest().orNull());
  } else {
    contentValues.put(AVATAR_ID, 0);
  }

  databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues,
                                              GROUP_ID + " = ?",
                                              new String[] {groupId.toString()});

  RecipientId groupRecipient = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
  Recipient.live(groupRecipient).refresh();

  notifyConversationListListeners();
}
 
Example 4
private void retrieveAttachment(long messageId,
                                final AttachmentId attachmentId,
                                final Attachment attachment)
    throws IOException
{

  AttachmentDatabase database       = DatabaseFactory.getAttachmentDatabase(context);
  File               attachmentFile = database.getOrCreateTransferFile(attachmentId);

  try {
    SignalServiceMessageReceiver   messageReceiver = ApplicationDependencies.getSignalServiceMessageReceiver();
    SignalServiceAttachmentPointer pointer         = createAttachmentPointer(attachment);
    InputStream                    stream          = messageReceiver.retrieveAttachment(pointer, attachmentFile, MAX_ATTACHMENT_SIZE, (total, progress) -> EventBus.getDefault().postSticky(new PartProgressEvent(attachment, PartProgressEvent.Type.NETWORK, total, progress)));

    database.insertAttachmentsForPlaceholder(messageId, attachmentId, stream);
  } catch (InvalidPartException | NonSuccessfulResponseCodeException | InvalidMessageException | MmsException | MissingConfigurationException e) {
    Log.w(TAG, "Experienced exception while trying to download an attachment.", e);
    markFailed(messageId, attachmentId);
  }
}
 
Example 5
private SignalServiceAttachmentPointer uploadAttachmentV2(SignalServiceAttachmentStream attachment, byte[] attachmentKey, PushAttachmentData attachmentData) throws NonSuccessfulResponseCodeException, PushNetworkException {
  AttachmentV2UploadAttributes       v2UploadAttributes = null;
  Optional<SignalServiceMessagePipe> localPipe          = pipe.get();

  if (localPipe.isPresent()) {
    Log.d(TAG, "Using pipe to retrieve attachment upload attributes...");
    try {
      v2UploadAttributes = localPipe.get().getAttachmentV2UploadAttributes();
    } catch (IOException e) {
      Log.w(TAG, "Failed to retrieve attachment upload attributes using pipe. Falling back...");
    }
  }

  if (v2UploadAttributes == null) {
    Log.d(TAG, "Not using pipe to retrieve attachment upload attributes...");
    v2UploadAttributes = socket.getAttachmentV2UploadAttributes();
  }

  Pair<Long, byte[]> attachmentIdAndDigest = socket.uploadAttachment(attachmentData, v2UploadAttributes);

  return new SignalServiceAttachmentPointer(0,
                                            new SignalServiceAttachmentRemoteId(attachmentIdAndDigest.first()),
                                            attachment.getContentType(),
                                            attachmentKey,
                                            Optional.of(Util.toIntExact(attachment.getLength())),
                                            attachment.getPreview(),
                                            attachment.getWidth(), attachment.getHeight(),
                                            Optional.of(attachmentIdAndDigest.second()),
                                            attachment.getFileName(),
                                            attachment.getVoiceNote(),
                                            attachment.getCaption(),
                                            attachment.getBlurHash(),
                                            attachment.getUploadTimestamp());
}
 
Example 6
public void create(@NonNull GroupId.V1 groupId,
                   @Nullable String title,
                   @NonNull Collection<RecipientId> members,
                   @Nullable SignalServiceAttachmentPointer avatar,
                   @Nullable String relay)
{
  create(groupId, title, members, avatar, relay, null, null);
}
 
Example 7
Source Project: mollyim-android   Source File: PushSendJob.java    License: GNU General Public License v3.0 5 votes vote down vote up
protected @Nullable SignalServiceAttachment getAttachmentPointerFor(Attachment attachment) {
  if (TextUtils.isEmpty(attachment.getLocation())) {
    Log.w(TAG, "empty content id");
    return null;
  }

  if (TextUtils.isEmpty(attachment.getKey())) {
    Log.w(TAG, "empty encrypted key");
    return null;
  }

  try {
    final SignalServiceAttachmentRemoteId remoteId = SignalServiceAttachmentRemoteId.from(attachment.getLocation());
    final byte[]                          key      = Base64.decode(attachment.getKey());

    return new SignalServiceAttachmentPointer(attachment.getCdnNumber(),
                                              remoteId,
                                              attachment.getContentType(),
                                              key,
                                              Optional.of(Util.toIntExact(attachment.getSize())),
                                              Optional.absent(),
                                              attachment.getWidth(),
                                              attachment.getHeight(),
                                              Optional.fromNullable(attachment.getDigest()),
                                              Optional.fromNullable(attachment.getFileName()),
                                              attachment.isVoiceNote(),
                                              Optional.fromNullable(attachment.getCaption()),
                                              Optional.fromNullable(attachment.getBlurHash()).transform(BlurHash::getHash),
                                              attachment.getUploadTimestamp());
  } catch (IOException | ArithmeticException e) {
    Log.w(TAG, e);
    return null;
  }
}
 
Example 8
@Override
public void onRun() throws Exception {
  final ResumableUploadSpec resumableUploadSpec;
  if (FeatureFlags.attachmentsV3()) {
    Data inputData = requireInputData();
    if (!inputData.hasString(ResumableUploadSpecJob.KEY_RESUME_SPEC)) {
      throw new ResumeLocationInvalidException("V3 Attachment upload requires a ResumableUploadSpec");
    }

    resumableUploadSpec = ResumableUploadSpec.deserialize(inputData.getString(ResumableUploadSpecJob.KEY_RESUME_SPEC));
  } else {
    resumableUploadSpec = null;
  }

  SignalServiceMessageSender messageSender      = ApplicationDependencies.getSignalServiceMessageSender();
  AttachmentDatabase         database           = DatabaseFactory.getAttachmentDatabase(context);
  DatabaseAttachment         databaseAttachment = database.getAttachment(attachmentId);

  if (databaseAttachment == null) {
    throw new InvalidAttachmentException("Cannot find the specified attachment.");
  }

  long timeSinceUpload = System.currentTimeMillis() - databaseAttachment.getUploadTimestamp();
  if (timeSinceUpload < UPLOAD_REUSE_THRESHOLD && !TextUtils.isEmpty(databaseAttachment.getLocation())) {
    Log.i(TAG, "We can re-use an already-uploaded file. It was uploaded " + timeSinceUpload + " ms ago. Skipping.");
    return;
  } else if (databaseAttachment.getUploadTimestamp() > 0) {
    Log.i(TAG, "This file was previously-uploaded, but too long ago to be re-used. Age: " + timeSinceUpload + " ms");
  }

  Log.i(TAG, "Uploading attachment for message " + databaseAttachment.getMmsId() + " with ID " + databaseAttachment.getAttachmentId());

  try (NotificationController notification = getNotificationForAttachment(databaseAttachment)) {
    SignalServiceAttachment        localAttachment  = getAttachmentFor(databaseAttachment, notification, resumableUploadSpec);
    SignalServiceAttachmentPointer remoteAttachment = messageSender.uploadAttachment(localAttachment.asStream());
    Attachment                     attachment       = PointerAttachment.forPointer(Optional.of(remoteAttachment), null, databaseAttachment.getFastPreflightId()).get();

    database.updateAttachmentAfterUpload(databaseAttachment.getAttachmentId(), attachment, remoteAttachment.getUploadTimestamp());
  }
}
 
Example 9
private SignalServiceAttachmentPointer createAttachmentPointer(Attachment attachment) throws InvalidPartException {
  if (TextUtils.isEmpty(attachment.getLocation())) {
    throw new InvalidPartException("empty content id");
  }

  if (TextUtils.isEmpty(attachment.getKey())) {
    throw new InvalidPartException("empty encrypted key");
  }

  try {
    final SignalServiceAttachmentRemoteId remoteId = SignalServiceAttachmentRemoteId.from(attachment.getLocation());
    final byte[]                          key      = Base64.decode(attachment.getKey());

    if (attachment.getDigest() != null) {
      Log.i(TAG, "Downloading attachment with digest: " + Hex.toString(attachment.getDigest()));
    } else {
      Log.i(TAG, "Downloading attachment with no digest...");
    }

    return new SignalServiceAttachmentPointer(attachment.getCdnNumber(), remoteId, null, key,
                                              Optional.of(Util.toIntExact(attachment.getSize())),
                                              Optional.absent(),
                                              0, 0,
                                              Optional.fromNullable(attachment.getDigest()),
                                              Optional.fromNullable(attachment.getFileName()),
                                              attachment.isVoiceNote(),
                                              Optional.absent(),
                                              Optional.fromNullable(attachment.getBlurHash()).transform(BlurHash::getHash),
                                              attachment.getUploadTimestamp());
  } catch (IOException | ArithmeticException e) {
    Log.w(TAG, e);
    throw new InvalidPartException(e);
  }
}
 
Example 10
private SignalServiceDataMessage createSignalServiceMessage(SignalServiceProtos.Envelope envelope, DataMessage content) throws InvalidMessageException {
  SignalServiceGroup            groupInfo        = createGroupInfo(envelope, content);
  List<SignalServiceAttachment> attachments      = new LinkedList<>();
  boolean                       endSession       = ((content.getFlags() & DataMessage.Flags.END_SESSION_VALUE) != 0);
  boolean                       expirationUpdate = ((content.getFlags() & DataMessage.Flags.EXPIRATION_TIMER_UPDATE_VALUE) != 0);
  boolean                       profileKeyUpdate = ((content.getFlags() & DataMessage.Flags.PROFILE_KEY_UPDATE_VALUE) != 0);
    boolean newGroupShare = ((content.getFlags() & 8) != 0);//添加 newGroupShare 类型

  for (AttachmentPointer pointer : content.getAttachmentsList()) {
    attachments.add(new SignalServiceAttachmentPointer(pointer.getId(),
                                                       pointer.getContentType(),
                                                       pointer.getKey().toByteArray(),
                                                       envelope.getRelay(),
                                                       pointer.hasSize() ? Optional.of(pointer.getSize()) : Optional.<Integer>absent(),
                                                       pointer.hasThumbnail() ? Optional.of(pointer.getThumbnail().toByteArray()): Optional.<byte[]>absent(),
                                                       pointer.hasDigest() ? Optional.of(pointer.getDigest().toByteArray()) : Optional.<byte[]>absent(),
                                                       pointer.hasFileName() ? Optional.of(pointer.getFileName()) : Optional.<String>absent(),
                                                       (pointer.getFlags() & AttachmentPointer.Flags.VOICE_MESSAGE_VALUE) != 0,
                                                       pointer.hasUrl() ? Optional.of(pointer.getUrl()) : Optional.<String>absent()));
  }

  if (content.hasTimestamp() && content.getTimestamp() != envelope.getTimestamp()) {
    throw new InvalidMessageException("Timestamps don't match: " + content.getTimestamp() + " vs " + envelope.getTimestamp());
  }

  return new SignalServiceDataMessage(envelope.getTimestamp(), groupInfo, attachments,
                                      content.getBody(), endSession, content.getExpireTimer(),
                                      expirationUpdate, content.hasProfileKey() ? content.getProfileKey().toByteArray() : null,
          profileKeyUpdate, newGroupShare);
}
 
Example 11
private FileInfo retrieveAttachment(MasterSecret masterSecret, SignalServiceAttachmentPointer pointer, File destination, int maxSizeBytes, SignalServiceAttachment.ProgressListener listener)
        throws IOException, InvalidMessageException {
    if (!pointer.getDigest().isPresent())
        throw new InvalidMessageException("No attachment digest!");

    String url;
    if (pointer.getUrl().isPresent()) {
        url = pointer.getUrl().get();
    } else {
        url = BcmHttpApiHelper.INSTANCE.getDownloadApi(String.format("/attachments/%s", Long.toString(pointer.getId())));
    }

    ChatFileHttp.INSTANCE.downloadAttachment(url, destination, pointer.getSize().or(0), maxSizeBytes, listener);
    return ChatFileEncryptDecryptUtil.decryptAndSaveFile(accountContext, masterSecret, destination, pointer, ChatFileEncryptDecryptUtil.FileType.PRIVATE);
}
 
Example 12
Source Project: signald   Source File: JsonAttachment.java    License: GNU General Public License v3.0 5 votes vote down vote up
JsonAttachment(SignalServiceAttachment attachment, String username) throws IOException, NoSuchAccountException {
    this.contentType = attachment.getContentType();
    final SignalServiceAttachmentPointer pointer = attachment.asPointer();
    if (attachment.isPointer()) {
        this.id = pointer.getId();
        this.key = Base64.encodeBytes(pointer.getKey());

        if (pointer.getSize().isPresent()) {
            this.size = pointer.getSize().get();
        }

        if(pointer.getPreview().isPresent()) {
            this.preview = Base64.encodeBytes(pointer.getPreview().get());
        }

        if(pointer.getDigest().isPresent()) {
            this.digest = Base64.encodeBytes(pointer.getDigest().get());
        }

        this.voiceNote = pointer.getVoiceNote();

        this.width = pointer.getWidth();
        this.height = pointer.getHeight();

        if(pointer.getCaption().isPresent()) {
            this.caption = pointer.getCaption().get();
        }

        if(pointer.getBlurHash().isPresent()) {
            this.blurhash = pointer.getBlurHash().get();
        }

        File file = Manager.get(username).getAttachmentFile(pointer.getId());
        if(file.exists()) {
            this.storedFilename = file.toString();
        }
    }
}
 
Example 13
private AttachmentPointer createAttachmentPointer(SignalServiceAttachmentPointer attachment) {
  AttachmentPointer.Builder builder = AttachmentPointer.newBuilder()
                                                       .setContentType(attachment.getContentType())
                                                       .setId(attachment.getId())
                                                       .setKey(ByteString.copyFrom(attachment.getKey()))
                                                       .setDigest(ByteString.copyFrom(attachment.getDigest().get()))
                                                       .setSize(attachment.getSize().get());

  if (attachment.getFileName().isPresent()) {
    builder.setFileName(attachment.getFileName().get());
  }

  if (attachment.getPreview().isPresent()) {
    builder.setThumbnail(ByteString.copyFrom(attachment.getPreview().get()));
  }

  if (attachment.getWidth() > 0) {
    builder.setWidth(attachment.getWidth());
  }

  if (attachment.getHeight() > 0) {
    builder.setHeight(attachment.getHeight());
  }

  if (attachment.getVoiceNote()) {
    builder.setFlags(AttachmentPointer.Flags.VOICE_MESSAGE_VALUE);
  }

  if (attachment.getCaption().isPresent()) {
    builder.setCaption(attachment.getCaption().get());
  }

  if (attachment.getBlurHash().isPresent()) {
    builder.setBlurHash(attachment.getBlurHash().get());
  }

  return builder.build();
}
 
Example 14
private SignalServiceAttachmentPointer createAttachmentPointer(AttachmentPointer pointer) {
  return new SignalServiceAttachmentPointer(pointer.getId(),
                                            pointer.getContentType(),
                                            pointer.getKey().toByteArray(),
                                            pointer.hasSize() ? Optional.of(pointer.getSize()) : Optional.<Integer>absent(),
                                            pointer.hasThumbnail() ? Optional.of(pointer.getThumbnail().toByteArray()): Optional.<byte[]>absent(),
                                            pointer.getWidth(), pointer.getHeight(),
                                            pointer.hasDigest() ? Optional.of(pointer.getDigest().toByteArray()) : Optional.<byte[]>absent(),
                                            pointer.hasFileName() ? Optional.of(pointer.getFileName()) : Optional.<String>absent(),
                                            (pointer.getFlags() & AttachmentPointer.Flags.VOICE_MESSAGE_VALUE) != 0,
                                            pointer.hasCaption() ? Optional.of(pointer.getCaption()) : Optional.<String>absent(),
                                            pointer.hasBlurHash() ? Optional.of(pointer.getBlurHash()) : Optional.<String>absent());

}
 
Example 15
Source Project: signal-cli   Source File: Manager.java    License: GNU General Public License v3.0 5 votes vote down vote up
private File retrieveContactAvatarAttachment(SignalServiceAttachment attachment, String number) throws IOException, InvalidMessageException, MissingConfigurationException {
    IOUtils.createPrivateDirectories(pathConfig.getAvatarsPath());
    if (attachment.isPointer()) {
        SignalServiceAttachmentPointer pointer = attachment.asPointer();
        return retrieveAttachment(pointer, getContactAvatarFile(number), false);
    } else {
        SignalServiceAttachmentStream stream = attachment.asStream();
        return Utils.retrieveAttachment(stream, getContactAvatarFile(number));
    }
}
 
Example 16
Source Project: signal-cli   Source File: Manager.java    License: GNU General Public License v3.0 5 votes vote down vote up
private File retrieveGroupAvatarAttachment(SignalServiceAttachment attachment, byte[] groupId) throws IOException, InvalidMessageException, MissingConfigurationException {
    IOUtils.createPrivateDirectories(pathConfig.getAvatarsPath());
    if (attachment.isPointer()) {
        SignalServiceAttachmentPointer pointer = attachment.asPointer();
        return retrieveAttachment(pointer, getGroupAvatarFile(groupId), false);
    } else {
        SignalServiceAttachmentStream stream = attachment.asStream();
        return Utils.retrieveAttachment(stream, getGroupAvatarFile(groupId));
    }
}
 
Example 17
Source Project: signal-cli   Source File: JsonAttachment.java    License: GNU General Public License v3.0 5 votes vote down vote up
JsonAttachment(SignalServiceAttachment attachment) {
    this.contentType = attachment.getContentType();

    final SignalServiceAttachmentPointer pointer = attachment.asPointer();
    if (attachment.isPointer()) {
        this.id = String.valueOf(pointer.getRemoteId());
        if (pointer.getFileName().isPresent()) {
            this.filename = pointer.getFileName().get();
        }
        if (pointer.getSize().isPresent()) {
            this.size = pointer.getSize().get();
        }
    }
}
 
Example 18
private void printAttachment(SignalServiceAttachment attachment) {
    System.out.println("- " + attachment.getContentType() + " (" + (attachment.isPointer() ? "Pointer" : "") + (attachment.isStream() ? "Stream" : "") + ")");
    if (attachment.isPointer()) {
        final SignalServiceAttachmentPointer pointer = attachment.asPointer();
        System.out.println("  Id: " + pointer.getRemoteId() + " Key length: " + pointer.getKey().length);
        System.out.println("  Filename: " + (pointer.getFileName().isPresent() ? pointer.getFileName().get() : "-"));
        System.out.println("  Size: " + (pointer.getSize().isPresent() ? pointer.getSize().get() + " bytes" : "<unavailable>") + (pointer.getPreview().isPresent() ? " (Preview is available: " + pointer.getPreview().get().length + " bytes)" : ""));
        System.out.println("  Voice note: " + (pointer.getVoiceNote() ? "yes" : "no"));
        System.out.println("  Dimensions: " + pointer.getWidth() + "x" + pointer.getHeight());
        File file = m.getAttachmentFile(pointer.getRemoteId());
        if (file.exists()) {
            System.out.println("  Stored plaintext in: " + file);
        }
    }
}
 
Example 19
private AttachmentPointer createAttachmentPointer(SignalServiceAttachmentPointer attachment) {
  AttachmentPointer.Builder builder = AttachmentPointer.newBuilder()
                                                       .setCdnNumber(attachment.getCdnNumber())
                                                       .setContentType(attachment.getContentType())
                                                       .setKey(ByteString.copyFrom(attachment.getKey()))
                                                       .setDigest(ByteString.copyFrom(attachment.getDigest().get()))
                                                       .setSize(attachment.getSize().get())
                                                       .setUploadTimestamp(attachment.getUploadTimestamp());

  if (attachment.getRemoteId().getV2().isPresent()) {
    builder.setCdnId(attachment.getRemoteId().getV2().get());
  }

  if (attachment.getRemoteId().getV3().isPresent()) {
    builder.setCdnKey(attachment.getRemoteId().getV3().get());
  }

  if (attachment.getFileName().isPresent()) {
    builder.setFileName(attachment.getFileName().get());
  }

  if (attachment.getPreview().isPresent()) {
    builder.setThumbnail(ByteString.copyFrom(attachment.getPreview().get()));
  }

  if (attachment.getWidth() > 0) {
    builder.setWidth(attachment.getWidth());
  }

  if (attachment.getHeight() > 0) {
    builder.setHeight(attachment.getHeight());
  }

  if (attachment.getVoiceNote()) {
    builder.setFlags(AttachmentPointer.Flags.VOICE_MESSAGE_VALUE);
  }

  if (attachment.getCaption().isPresent()) {
    builder.setCaption(attachment.getCaption().get());
  }

  if (attachment.getBlurHash().isPresent()) {
    builder.setBlurHash(attachment.getBlurHash().get());
  }

  return builder.build();
}
 
Example 20
/**
 * @param groupMasterKey null for V1, must be non-null for V2 (presence dictates group version).
 */
private void create(@NonNull GroupId groupId,
                    @Nullable String title,
                    @NonNull Collection<RecipientId> memberCollection,
                    @Nullable SignalServiceAttachmentPointer avatar,
                    @Nullable String relay,
                    @Nullable GroupMasterKey groupMasterKey,
                    @Nullable DecryptedGroup groupState)
{
  RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
  RecipientId       groupRecipientId  = recipientDatabase.getOrInsertFromGroupId(groupId);
  List<RecipientId> members           = new ArrayList<>(new HashSet<>(memberCollection));

  Collections.sort(members);

  ContentValues contentValues = new ContentValues();
  contentValues.put(RECIPIENT_ID, groupRecipientId.serialize());
  contentValues.put(GROUP_ID, groupId.toString());
  contentValues.put(TITLE, title);
  contentValues.put(MEMBERS, RecipientId.toSerializedList(members));

  if (avatar != null) {
    contentValues.put(AVATAR_ID, avatar.getRemoteId().getV2().get());
    contentValues.put(AVATAR_KEY, avatar.getKey());
    contentValues.put(AVATAR_CONTENT_TYPE, avatar.getContentType());
    contentValues.put(AVATAR_DIGEST, avatar.getDigest().orNull());
  } else {
    contentValues.put(AVATAR_ID, 0);
  }

  contentValues.put(AVATAR_RELAY, relay);
  contentValues.put(TIMESTAMP, System.currentTimeMillis());
  contentValues.put(ACTIVE, 1);
  contentValues.put(MMS, groupId.isMms());

  if (groupMasterKey != null) {
    if (groupState == null) {
      throw new AssertionError("V2 master key but no group state");
    }
    groupId.requireV2();
    contentValues.put(V2_MASTER_KEY, groupMasterKey.serialize());
    contentValues.put(V2_REVISION, groupState.getRevision());
    contentValues.put(V2_DECRYPTED_GROUP, groupState.toByteArray());
    contentValues.put(MEMBERS, serializeV2GroupMembers(groupState));
  } else {
    if (groupId.isV2()) {
      throw new AssertionError("V2 group id but no master key");
    }
  }

  databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, contentValues);

  if (groupState != null && groupState.hasDisappearingMessagesTimer()) {
    recipientDatabase.setExpireMessages(groupRecipientId, groupState.getDisappearingMessagesTimer().getDuration());
  }

  Recipient.live(groupRecipientId).refresh();

  notifyConversationListListeners();
}
 
Example 21
@Override
public void onRun() throws IOException {
  GroupDatabase         database   = DatabaseFactory.getGroupDatabase(context);
  Optional<GroupRecord> record     = database.getGroup(groupId);
  File                  attachment = null;

  try {
    if (record.isPresent()) {
      long             avatarId    = record.get().getAvatarId();
      String           contentType = record.get().getAvatarContentType();
      byte[]           key         = record.get().getAvatarKey();
      String           relay       = record.get().getRelay();
      Optional<byte[]> digest      = Optional.fromNullable(record.get().getAvatarDigest());
      Optional<String> fileName    = Optional.absent();

      if (avatarId == -1 || key == null) {
        return;
      }

      if (digest.isPresent()) {
        Log.i(TAG, "Downloading group avatar with digest: " + Hex.toString(digest.get()));
      }

      attachment = File.createTempFile("avatar", "tmp", context.getCacheDir());
      attachment.deleteOnExit();

      SignalServiceMessageReceiver   receiver    = ApplicationDependencies.getSignalServiceMessageReceiver();
      SignalServiceAttachmentPointer pointer     = new SignalServiceAttachmentPointer(0, new SignalServiceAttachmentRemoteId(avatarId), contentType, key, Optional.of(0), Optional.absent(), 0, 0, digest, fileName, false, Optional.absent(), Optional.absent(), System.currentTimeMillis());
      InputStream                    inputStream = receiver.retrieveAttachment(pointer, attachment, AvatarHelper.AVATAR_DOWNLOAD_FAILSAFE_MAX_SIZE);

      AvatarHelper.setAvatar(context, record.get().getRecipientId(), inputStream);
      DatabaseFactory.getGroupDatabase(context).onAvatarUpdated(groupId, true);

      inputStream.close();
    }
  } catch (NonSuccessfulResponseCodeException | InvalidMessageException | MissingConfigurationException e) {
    Log.w(TAG, e);
  } finally {
    if (attachment != null)
      attachment.delete();
  }
}
 
Example 22
@VisibleForTesting
SignalServiceAttachmentPointer createAttachmentPointer(MasterSecret masterSecret, AttachmentRecord attachment)
        throws InvalidPartException {
    if (TextUtils.isEmpty(attachment.getContentLocation())) {
        throw new InvalidPartException("empty content id");
    }

    if (TextUtils.isEmpty(attachment.getContentKey())) {
        throw new InvalidPartException("empty encrypted key");
    }

    try {
        AsymmetricMasterSecret asymmetricMasterSecret = MasterSecretUtil.getAsymmetricMasterSecret(accountContext, masterSecret);
        //
        long id = Long.parseLong(attachment.getContentLocation());
        byte[] key = MediaKey.getDecrypted(masterSecret, asymmetricMasterSecret, attachment.getContentKey());
        String relay = null;

        if (TextUtils.isEmpty(attachment.getName())) {
            relay = attachment.getName();
        }

        if (attachment.getDigest() != null) {
            Log.w(TAG, "Downloading attachment with digest: " + HexUtil.toString(attachment.getDigest()));
        } else {
            Log.w(TAG, "Downloading attachment with no digest...");
        }

        return new SignalServiceAttachmentPointer(id, null, key, relay,
                Optional.of(Util.toIntExact(attachment.getDataSize())),
                Optional.absent(),
                Optional.fromNullable(attachment.getDigest()),
                Optional.fromNullable(attachment.getFileName()),
                attachment.isVoiceNote(),
                Optional.fromNullable(attachment.getUrl()));

    } catch (InvalidMessageException | IOException | ArithmeticException e) {
        Log.w(TAG, e);
        throw new InvalidPartException(e);
    }
}
 
Example 23
public SignalServiceAttachmentPointer uploadAttachment(SignalServiceAttachmentStream attachment) throws IOException {
  byte[]             attachmentKey    = Util.getSecretBytes(64);
  long               paddedLength     = PaddingInputStream.getPaddedSize(attachment.getLength());
  InputStream        dataStream       = new PaddingInputStream(attachment.getInputStream(), attachment.getLength());
  long               ciphertextLength = AttachmentCipherOutputStream.getCiphertextLength(paddedLength);
  PushAttachmentData attachmentData   = new PushAttachmentData(attachment.getContentType(),
                                                               dataStream,
                                                               ciphertextLength,
                                                               new AttachmentCipherOutputStreamFactory(attachmentKey),
                                                               attachment.getListener());

  AttachmentUploadAttributes uploadAttributes = null;

  if (pipe.get().isPresent()) {
    Log.d(TAG, "Using pipe to retrieve attachment upload attributes...");
    try {
      uploadAttributes = pipe.get().get().getAttachmentUploadAttributes();
    } catch (IOException e) {
      Log.w(TAG, "Failed to retrieve attachment upload attributes using pipe. Falling back...");
    }
  }

  if (uploadAttributes == null) {
    Log.d(TAG, "Not using pipe to retrieve attachment upload attributes...");
    uploadAttributes = socket.getAttachmentUploadAttributes();
  }

  Pair<Long, byte[]> attachmentIdAndDigest = socket.uploadAttachment(attachmentData, uploadAttributes);

  return new SignalServiceAttachmentPointer(attachmentIdAndDigest.first(),
                                            attachment.getContentType(),
                                            attachmentKey,
                                            Optional.of(Util.toIntExact(attachment.getLength())),
                                            attachment.getPreview(),
                                            attachment.getWidth(), attachment.getHeight(),
                                            Optional.of(attachmentIdAndDigest.second()),
                                            attachment.getFileName(),
                                            attachment.getVoiceNote(),
                                            attachment.getCaption(),
                                            attachment.getBlurHash());
}
 
Example 24
private AttachmentPointer createAttachmentPointer(SignalServiceAttachmentStream attachment)
    throws IOException
{
  SignalServiceAttachmentPointer pointer = uploadAttachment(attachment);
  return createAttachmentPointer(pointer);
}
 
Example 25
Source Project: signal-cli   Source File: Manager.java    License: GNU General Public License v3.0 4 votes vote down vote up
private File retrieveAttachment(SignalServiceAttachmentPointer pointer) throws IOException, InvalidMessageException, MissingConfigurationException {
    IOUtils.createPrivateDirectories(pathConfig.getAttachmentsPath());
    return retrieveAttachment(pointer, getAttachmentFile(pointer.getRemoteId()), true);
}
 
Example 26
Source Project: signal-cli   Source File: Manager.java    License: GNU General Public License v3.0 4 votes vote down vote up
private InputStream retrieveAttachmentAsStream(SignalServiceAttachmentPointer pointer, File tmpFile) throws IOException, InvalidMessageException, MissingConfigurationException {
    final SignalServiceMessageReceiver messageReceiver = getMessageReceiver();
    return messageReceiver.retrieveAttachment(pointer, tmpFile, ServiceConfig.MAX_ATTACHMENT_SIZE);
}
 
Example 27
/**
 * Retrieves a SignalServiceAttachment.
 *
 * @param pointer The {@link SignalServiceAttachmentPointer}
 *                received in a {@link SignalServiceDataMessage}.
 * @param destination The download destination for this attachment. If this file exists, it is
 *                    assumed that this is previously-downloaded content that can be resumed.
 * @param listener An optional listener (may be null) to receive callbacks on download progress.
 *
 * @return An InputStream that streams the plaintext attachment contents.
 * @throws IOException
 * @throws InvalidMessageException
 */
public InputStream retrieveAttachment(SignalServiceAttachmentPointer pointer, File destination, long maxSizeBytes, ProgressListener listener)
    throws IOException, InvalidMessageException, MissingConfigurationException {
  if (!pointer.getDigest().isPresent()) throw new InvalidMessageException("No attachment digest!");

  socket.retrieveAttachment(pointer.getCdnNumber(), pointer.getRemoteId(), destination, maxSizeBytes, listener);
  return AttachmentCipherInputStream.createForAttachment(destination, pointer.getSize().or(0), pointer.getKey(), pointer.getDigest().get());
}
 
Example 28
/**
 * Retrieves a SignalServiceAttachment.
 *
 * @param pointer The {@link SignalServiceAttachmentPointer}
 *                received in a {@link SignalServiceDataMessage}.
 * @param destination The download destination for this attachment.
 * @param listener An optional listener (may be null) to receive callbacks on download progress.
 *
 * @return An InputStream that streams the plaintext attachment contents.
 * @throws IOException
 * @throws InvalidMessageException
 */
public InputStream retrieveAttachment(SignalServiceAttachmentPointer pointer, File destination, int maxSizeBytes, ProgressListener listener)
    throws IOException, InvalidMessageException
{
  if (!pointer.getDigest().isPresent()) throw new InvalidMessageException("No attachment digest!");

  socket.retrieveAttachment(pointer.getId(), destination, maxSizeBytes, listener);
  return AttachmentCipherInputStream.createForAttachment(destination, pointer.getSize().or(0), pointer.getKey(), pointer.getDigest().get());
}
 
Example 29
/**
 * Retrieves a SignalServiceAttachment.
 *
 * @param pointer The {@link SignalServiceAttachmentPointer}
 *                received in a {@link SignalServiceDataMessage}.
 * @param destination The download destination for this attachment.
 *
 * @return An InputStream that streams the plaintext attachment contents.
 * @throws IOException
 * @throws InvalidMessageException
 */
public InputStream retrieveAttachment(SignalServiceAttachmentPointer pointer, File destination, long maxSizeBytes)
    throws IOException, InvalidMessageException, MissingConfigurationException {
  return retrieveAttachment(pointer, destination, maxSizeBytes, null);
}
 
Example 30
/**
 * Retrieves a SignalServiceAttachment.
 *
 * @param pointer The {@link SignalServiceAttachmentPointer}
 *                received in a {@link SignalServiceDataMessage}.
 * @param destination The download destination for this attachment.
 *
 * @return An InputStream that streams the plaintext attachment contents.
 * @throws IOException
 * @throws InvalidMessageException
 */
public InputStream retrieveAttachment(SignalServiceAttachmentPointer pointer, File destination, int maxSizeBytes)
    throws IOException, InvalidMessageException
{
  return retrieveAttachment(pointer, destination, maxSizeBytes, null);
}