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

The following examples show how to use org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer. 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
Source File: SignalServiceMessageSender.java    From mollyim-android with GNU General Public License v3.0 6 votes vote down vote up
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 #2
Source File: GroupDatabase.java    From mollyim-android with GNU General Public License v3.0 6 votes vote down vote up
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 #3
Source File: SignalServiceMessageSender.java    From mollyim-android with GNU General Public License v3.0 6 votes vote down vote up
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 #4
Source File: AttachmentDownloadJob.java    From mollyim-android with GNU General Public License v3.0 6 votes vote down vote up
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
Source File: AttachmentDownloadJob.java    From bcm-android with GNU General Public License v3.0 5 votes vote down vote up
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 #6
Source File: ReceiveMessageHandler.java    From signal-cli with GNU General Public License v3.0 5 votes vote down vote up
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 #7
Source File: JsonAttachment.java    From signal-cli with 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 #8
Source File: Manager.java    From signal-cli with 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 #9
Source File: Manager.java    From signal-cli with 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 #10
Source File: SignalServiceCipher.java    From libsignal-service-java with GNU General Public License v3.0 5 votes vote down vote up
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 #11
Source File: SignalServiceMessageSender.java    From libsignal-service-java with GNU General Public License v3.0 5 votes vote down vote up
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 #12
Source File: JsonAttachment.java    From signald with 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
Source File: SignalServiceCipher.java    From bcm-android with GNU General Public License v3.0 5 votes vote down vote up
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 #14
Source File: AttachmentDownloadJob.java    From mollyim-android with GNU General Public License v3.0 5 votes vote down vote up
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 #15
Source File: AttachmentUploadJob.java    From mollyim-android with GNU General Public License v3.0 5 votes vote down vote up
@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 #16
Source File: SignalServiceMessageSender.java    From mollyim-android with GNU General Public License v3.0 5 votes vote down vote up
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 #17
Source File: PushSendJob.java    From mollyim-android with 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 #18
Source File: GroupDatabase.java    From mollyim-android with GNU General Public License v3.0 5 votes vote down vote up
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 #19
Source File: AvatarGroupsV1DownloadJob.java    From mollyim-android with GNU General Public License v3.0 4 votes vote down vote up
@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 #20
Source File: SignalServiceMessageSender.java    From mollyim-android with GNU General Public License v3.0 4 votes vote down vote up
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 #21
Source File: Manager.java    From signal-cli with 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 #22
Source File: Manager.java    From signal-cli with 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 #23
Source File: SignalServiceMessageSender.java    From libsignal-service-java with GNU General Public License v3.0 4 votes vote down vote up
private AttachmentPointer createAttachmentPointer(SignalServiceAttachmentStream attachment)
    throws IOException
{
  SignalServiceAttachmentPointer pointer = uploadAttachment(attachment);
  return createAttachmentPointer(pointer);
}
 
Example #24
Source File: GroupDatabase.java    From mollyim-android with GNU General Public License v3.0 4 votes vote down vote up
/**
 * @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 #25
Source File: SignalServiceMessageSender.java    From libsignal-service-java with GNU General Public License v3.0 4 votes vote down vote up
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 #26
Source File: AttachmentDownloadJob.java    From bcm-android with GNU General Public License v3.0 4 votes vote down vote up
@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 #27
Source File: SignalServiceMessageReceiver.java    From libsignal-service-java with GNU General Public License v3.0 3 votes vote down vote up
/**
 * 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 #28
Source File: SignalServiceMessageReceiver.java    From mollyim-android with GNU General Public License v3.0 3 votes vote down vote up
/**
 * 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 #29
Source File: SignalServiceMessageReceiver.java    From libsignal-service-java with GNU General Public License v3.0 2 votes vote down vote up
/**
 * 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);
}
 
Example #30
Source File: SignalServiceMessageReceiver.java    From mollyim-android with GNU General Public License v3.0 2 votes vote down vote up
/**
 * 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);
}