Java Code Examples for org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException

The following examples show how to use org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException. 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 ProfileAndCredential retrieveProfile(SignalServiceAddress address,
                                            Optional<ProfileKey> profileKey,
                                            Optional<UnidentifiedAccess> unidentifiedAccess,
                                            SignalServiceProfile.RequestType requestType)
    throws NonSuccessfulResponseCodeException, PushNetworkException, VerificationFailedException
{
  Optional<UUID> uuid = address.getUuid();

  if (uuid.isPresent() && profileKey.isPresent()) {
    if (requestType == SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL) {
      return socket.retrieveVersionedProfileAndCredential(uuid.get(), profileKey.get(), unidentifiedAccess);
    } else {
      return new ProfileAndCredential(socket.retrieveVersionedProfile(uuid.get(), profileKey.get(), unidentifiedAccess),
                                      SignalServiceProfile.RequestType.PROFILE,
                                      Optional.absent());
    }
  } else {
    return new ProfileAndCredential(socket.retrieveProfile(address, unidentifiedAccess),
                                    SignalServiceProfile.RequestType.PROFILE,
                                    Optional.absent());
  }
}
 
Example 2
public void requestSmsVerificationCode(boolean androidSmsRetriever, Optional<String> captchaToken, Optional<String> challenge) throws IOException {
  String path = String.format(CREATE_ACCOUNT_SMS_PATH, credentialsProvider.getE164(), androidSmsRetriever ? "android-ng" : "android");

  if (captchaToken.isPresent()) {
    path += "&captcha=" + captchaToken.get();
  } else if (challenge.isPresent()) {
    path += "&challenge=" + challenge.get();
  }

  makeServiceRequest(path, "GET", null, NO_HEADERS, new ResponseCodeHandler() {
    @Override
    public void handle(int responseCode) throws NonSuccessfulResponseCodeException {
      if (responseCode == 402) {
        throw new CaptchaRequiredException();
      }
    }
  });
}
 
Example 3
public void requestVoiceVerificationCode(Locale locale, Optional<String> captchaToken, Optional<String> challenge) throws IOException {
  Map<String, String> headers = locale != null ? Collections.singletonMap("Accept-Language", locale.getLanguage() + "-" + locale.getCountry()) : NO_HEADERS;
  String              path    = String.format(CREATE_ACCOUNT_VOICE_PATH, credentialsProvider.getE164());

  if (captchaToken.isPresent()) {
    path += "?captcha=" + captchaToken.get();
  } else if (challenge.isPresent()) {
    path += "?challenge=" + challenge.get();
  }

  makeServiceRequest(path, "GET", null, headers, new ResponseCodeHandler() {
    @Override
    public void handle(int responseCode) throws NonSuccessfulResponseCodeException {
      if (responseCode == 402) {
        throw new CaptchaRequiredException();
      }
    }
  });
}
 
Example 4
public ProfileAndCredential retrieveVersionedProfileAndCredential(UUID target, ProfileKey profileKey, Optional<UnidentifiedAccess> unidentifiedAccess)
    throws NonSuccessfulResponseCodeException, PushNetworkException, VerificationFailedException
{
  ProfileKeyVersion                  profileKeyIdentifier = profileKey.getProfileKeyVersion(target);
  ProfileKeyCredentialRequestContext requestContext       = clientZkProfileOperations.createProfileKeyCredentialRequestContext(random, target, profileKey);
  ProfileKeyCredentialRequest        request              = requestContext.getRequest();

  String version           = profileKeyIdentifier.serialize();
  String credentialRequest = Hex.toStringCondensed(request.serialize());
  String subPath           = String.format("%s/%s/%s", target, version, credentialRequest);

  String response = makeServiceRequest(String.format(PROFILE_PATH, subPath), "GET", null, NO_HEADERS, unidentifiedAccess);

  try {
    SignalServiceProfile signalServiceProfile = JsonUtil.fromJson(response, SignalServiceProfile.class);

    ProfileKeyCredential profileKeyCredential = signalServiceProfile.getProfileKeyCredentialResponse() != null
                                              ? clientZkProfileOperations.receiveProfileKeyCredential(requestContext, signalServiceProfile.getProfileKeyCredentialResponse())
                                              : null;

    return new ProfileAndCredential(signalServiceProfile, SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL, Optional.fromNullable(profileKeyCredential));
  } catch (IOException e) {
    Log.w(TAG, e);
    throw new NonSuccessfulResponseCodeException("Unable to parse entity");
  }
}
 
Example 5
public SignalServiceProfile retrieveVersionedProfile(UUID target, ProfileKey profileKey, Optional<UnidentifiedAccess> unidentifiedAccess)
    throws NonSuccessfulResponseCodeException, PushNetworkException
{
  ProfileKeyVersion profileKeyIdentifier = profileKey.getProfileKeyVersion(target);

  String version = profileKeyIdentifier.serialize();
  String subPath = String.format("%s/%s", target, version);

  String response = makeServiceRequest(String.format(PROFILE_PATH, subPath), "GET", null, NO_HEADERS, unidentifiedAccess);

  try {
    return JsonUtil.fromJson(response, SignalServiceProfile.class);
  } catch (IOException e) {
    Log.w(TAG, e);
    throw new NonSuccessfulResponseCodeException("Unable to parse entity");
  }
}
 
Example 6
private static Pair<RemoteAttestationResponse, List<String>> getRemoteAttestation(PushServiceSocket socket,
                                                                                  PushServiceSocket.ClientSet clientSet,
                                                                                  String authorization,
                                                                                  RemoteAttestationRequest request,
                                                                                  String enclaveName)
  throws IOException
{
  Response response       = socket.makeRequest(clientSet, authorization, new LinkedList<String>(), "/v1/attestation/" + enclaveName, "PUT", JsonUtil.toJson(request));
  ResponseBody body       = response.body();
  List<String> rawCookies = response.headers("Set-Cookie");
  List<String> cookies    = new LinkedList<>();

  for (String cookie : rawCookies) {
    cookies.add(cookie.split(";")[0]);
  }

  if (body != null) {
    return new Pair<>(JsonUtil.fromJson(body.string(), RemoteAttestationResponse.class), cookies);
  } else {
    throw new NonSuccessfulResponseCodeException("Empty response!");
  }
}
 
Example 7
Source Project: mollyim-android   Source File: ProfileUtil.java    License: GNU General Public License v3.0 6 votes vote down vote up
@WorkerThread
public static @NonNull ProfileAndCredential retrieveProfile(@NonNull Context context,
                                                            @NonNull Recipient recipient,
                                                            @NonNull SignalServiceProfile.RequestType requestType)
  throws IOException
{
  SignalServiceAddress         address            = RecipientUtil.toSignalServiceAddress(context, recipient);
  Optional<UnidentifiedAccess> unidentifiedAccess = getUnidentifiedAccess(context, recipient);
  Optional<ProfileKey>         profileKey         = ProfileKeyUtil.profileKeyOptional(recipient.getProfileKey());

  ProfileAndCredential profile;

  try {
    profile = retrieveProfileInternal(address, profileKey, unidentifiedAccess, requestType);
  } catch (NonSuccessfulResponseCodeException e) {
    if (unidentifiedAccess.isPresent()) {
      profile = retrieveProfileInternal(address, profileKey, Optional.absent(), requestType);
    } else {
      throw e;
    }
  }

  return profile;
}
 
Example 8
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 9
public void requestSmsVerificationCode(boolean androidSmsRetriever, Optional<String> captchaToken, Optional<String> challenge) throws IOException {
  String path = String.format(CREATE_ACCOUNT_SMS_PATH, credentialsProvider.getE164(), androidSmsRetriever ? "android-ng" : "android");

  if (captchaToken.isPresent()) {
    path += "&captcha=" + captchaToken.get();
  } else if (challenge.isPresent()) {
    path += "&challenge=" + challenge.get();
  }

  makeServiceRequest(path, "GET", null, NO_HEADERS, new ResponseCodeHandler() {
    @Override
    public void handle(int responseCode) throws NonSuccessfulResponseCodeException {
      if (responseCode == 402) {
        throw new CaptchaRequiredException();
      }
    }
  });
}
 
Example 10
public void requestVoiceVerificationCode(Locale locale, Optional<String> captchaToken, Optional<String> challenge) throws IOException {
  Map<String, String> headers = locale != null ? Collections.singletonMap("Accept-Language", locale.getLanguage() + "-" + locale.getCountry()) : NO_HEADERS;
  String              path    = String.format(CREATE_ACCOUNT_VOICE_PATH, credentialsProvider.getE164());

  if (captchaToken.isPresent()) {
    path += "?captcha=" + captchaToken.get();
  } else if (challenge.isPresent()) {
    path += "?challenge=" + challenge.get();
  }
  
  makeServiceRequest(path, "GET", null, headers, new ResponseCodeHandler() {
    @Override
    public void handle(int responseCode) throws NonSuccessfulResponseCodeException {
      if (responseCode == 402) {
        throw new CaptchaRequiredException();
      }
    }
  });
}
 
Example 11
public void setProfileAvatar(ProfileAvatarData profileAvatar)
    throws NonSuccessfulResponseCodeException, PushNetworkException
{
  String                        response       = makeServiceRequest(String.format(PROFILE_PATH, "form/avatar"), "GET", null);
  ProfileAvatarUploadAttributes formAttributes;

  try {
    formAttributes = JsonUtil.fromJson(response, ProfileAvatarUploadAttributes.class);
  } catch (IOException e) {
    Log.w(TAG, e);
    throw new NonSuccessfulResponseCodeException("Unable to parse entity");
  }

  if (profileAvatar != null) {
    uploadToCdn("", formAttributes.getAcl(), formAttributes.getKey(),
                formAttributes.getPolicy(), formAttributes.getAlgorithm(),
                formAttributes.getCredential(), formAttributes.getDate(),
                formAttributes.getSignature(), profileAvatar.getData(),
                profileAvatar.getContentType(), profileAvatar.getDataLength(),
                profileAvatar.getOutputStreamFactory(), null);
  }
}
 
Example 12
public Pair<RemoteAttestationResponse, List<String>> getContactDiscoveryRemoteAttestation(String authorization, RemoteAttestationRequest request, String mrenclave)
    throws IOException
{
  Response     response   = makeContactDiscoveryRequest(authorization, new LinkedList<String>(), "/v1/attestation/" + mrenclave, "PUT", JsonUtil.toJson(request));
  ResponseBody body       = response.body();
  List<String> rawCookies = response.headers("Set-Cookie");
  List<String> cookies    = new LinkedList<>();

  for (String cookie : rawCookies) {
    cookies.add(cookie.split(";")[0]);
  }

  if (body != null) {
    return new Pair<>(JsonUtil.fromJson(body.string(), RemoteAttestationResponse.class), cookies);
  } else {
    throw new NonSuccessfulResponseCodeException("Empty response!");
  }
}
 
Example 13
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 14
public void retrieveAttachment(int cdnNumber, SignalServiceAttachmentRemoteId cdnPath, File destination, long maxSizeBytes, ProgressListener listener)
    throws NonSuccessfulResponseCodeException, PushNetworkException, MissingConfigurationException {
  final String path;
  if (cdnPath.getV2().isPresent()) {
    path = String.format(Locale.US, ATTACHMENT_ID_DOWNLOAD_PATH, cdnPath.getV2().get());
  } else {
    path = String.format(Locale.US, ATTACHMENT_KEY_DOWNLOAD_PATH, cdnPath.getV3().get());
  }
  downloadFromCdn(destination, cdnNumber, path, maxSizeBytes, listener);
}
 
Example 15
public byte[] retrieveSticker(byte[] packId, int stickerId)
    throws NonSuccessfulResponseCodeException, PushNetworkException {
  String                hexPackId = Hex.toStringCondensed(packId);
  ByteArrayOutputStream output    = new ByteArrayOutputStream();

  try {
    downloadFromCdn(output, 0, 0, String.format(Locale.US, STICKER_PATH, hexPackId, stickerId), 1024 * 1024, null);
  } catch (MissingConfigurationException e) {
    throw new AssertionError(e);
  }

  return output.toByteArray();
}
 
Example 16
public byte[] retrieveStickerManifest(byte[] packId)
    throws NonSuccessfulResponseCodeException, PushNetworkException {
  String                hexPackId = Hex.toStringCondensed(packId);
  ByteArrayOutputStream output    = new ByteArrayOutputStream();

  try {
    downloadFromCdn(output, 0, 0, String.format(STICKER_MANIFEST_PATH, hexPackId), 1024 * 1024, null);
  } catch (MissingConfigurationException e) {
    throw new AssertionError(e);
  }

  return output.toByteArray();
}
 
Example 17
public SignalServiceProfile retrieveProfile(SignalServiceAddress target, Optional<UnidentifiedAccess> unidentifiedAccess)
    throws NonSuccessfulResponseCodeException, PushNetworkException
{
  String response = makeServiceRequest(String.format(PROFILE_PATH, target.getIdentifier()), "GET", null, NO_HEADERS, unidentifiedAccess);

  try {
    return JsonUtil.fromJson(response, SignalServiceProfile.class);
  } catch (IOException e) {
    Log.w(TAG, e);
    throw new NonSuccessfulResponseCodeException("Unable to parse entity");
  }
}
 
Example 18
public SignalServiceProfile retrieveProfileByUsername(String username, Optional<UnidentifiedAccess> unidentifiedAccess)
    throws NonSuccessfulResponseCodeException, PushNetworkException
{
  String response = makeServiceRequest(String.format(PROFILE_USERNAME_PATH, username), "GET", null, NO_HEADERS, unidentifiedAccess);

  try {
    return JsonUtil.fromJson(response, SignalServiceProfile.class);
  } catch (IOException e) {
    Log.w(TAG, e);
    throw new NonSuccessfulResponseCodeException("Unable to parse entity");
  }
}
 
Example 19
public void retrieveProfileAvatar(String path, File destination, long maxSizeBytes)
    throws NonSuccessfulResponseCodeException, PushNetworkException {
  try {
    downloadFromCdn(destination, 0, path, maxSizeBytes, null);
  } catch (MissingConfigurationException e) {
    throw new AssertionError(e);
  }
}
 
Example 20
public void setProfileName(String name) throws NonSuccessfulResponseCodeException, PushNetworkException {
  if (FeatureFlags.DISALLOW_OLD_PROFILE_SETTING) {
    throw new AssertionError();
  }

  makeServiceRequest(String.format(PROFILE_PATH, "name/" + (name == null ? "" : URLEncoder.encode(name))), "PUT", "");
}
 
Example 21
public Optional<String> setProfileAvatar(ProfileAvatarData profileAvatar)
    throws NonSuccessfulResponseCodeException, PushNetworkException
{
  if (FeatureFlags.DISALLOW_OLD_PROFILE_SETTING) {
    throw new AssertionError();
  }

  String                        response       = makeServiceRequest(String.format(PROFILE_PATH, "form/avatar"), "GET", null);
  ProfileAvatarUploadAttributes formAttributes;

  try {
    formAttributes = JsonUtil.fromJson(response, ProfileAvatarUploadAttributes.class);
  } catch (IOException e) {
    Log.w(TAG, e);
    throw new NonSuccessfulResponseCodeException("Unable to parse entity");
  }

  if (profileAvatar != null) {
    uploadToCdn0(AVATAR_UPLOAD_PATH, formAttributes.getAcl(), formAttributes.getKey(),
                formAttributes.getPolicy(), formAttributes.getAlgorithm(),
                formAttributes.getCredential(), formAttributes.getDate(),
                formAttributes.getSignature(), profileAvatar.getData(),
                profileAvatar.getContentType(), profileAvatar.getDataLength(),
                profileAvatar.getOutputStreamFactory(), null, null);

    return Optional.of(formAttributes.getKey());
  }

  return Optional.absent();
}
 
Example 22
/**
 * @return The avatar URL path, if one was written.
 */
public Optional<String> writeProfile(SignalServiceProfileWrite signalServiceProfileWrite, ProfileAvatarData profileAvatar)
    throws NonSuccessfulResponseCodeException, PushNetworkException
{
  String                        requestBody    = JsonUtil.toJson(signalServiceProfileWrite);
  ProfileAvatarUploadAttributes formAttributes;

  String response = makeServiceRequest(String.format(PROFILE_PATH, ""), "PUT", requestBody);

  if (signalServiceProfileWrite.hasAvatar() && profileAvatar != null) {
     try {
      formAttributes = JsonUtil.fromJson(response, ProfileAvatarUploadAttributes.class);
    } catch (IOException e) {
      Log.w(TAG, e);
      throw new NonSuccessfulResponseCodeException("Unable to parse entity");
    }

    uploadToCdn0(AVATAR_UPLOAD_PATH, formAttributes.getAcl(), formAttributes.getKey(),
                formAttributes.getPolicy(), formAttributes.getAlgorithm(),
                formAttributes.getCredential(), formAttributes.getDate(),
                formAttributes.getSignature(), profileAvatar.getData(),
                profileAvatar.getContentType(), profileAvatar.getDataLength(),
                profileAvatar.getOutputStreamFactory(), null, null);

     return Optional.of(formAttributes.getKey());
  }

  return Optional.absent();
}
 
Example 23
public void setUsername(String username) throws IOException {
  makeServiceRequest(String.format(SET_USERNAME_PATH, username), "PUT", "", NO_HEADERS, new ResponseCodeHandler() {
    @Override
    public void handle(int responseCode) throws NonSuccessfulResponseCodeException {
      switch (responseCode) {
        case 400: throw new UsernameMalformedException();
        case 409: throw new UsernameTakenException();
      }
    }
  }, Optional.<UnidentifiedAccess>absent());
}
 
Example 24
public List<ContactTokenDetails> retrieveDirectory(Set<String> contactTokens)
    throws NonSuccessfulResponseCodeException, PushNetworkException
{
  try {
    ContactTokenList        contactTokenList = new ContactTokenList(new LinkedList<>(contactTokens));
    String                  response         = makeServiceRequest(DIRECTORY_TOKENS_PATH, "PUT", JsonUtil.toJson(contactTokenList));
    ContactTokenDetailsList activeTokens     = JsonUtil.fromJson(response, ContactTokenDetailsList.class);

    return activeTokens.getContacts();
  } catch (IOException e) {
    Log.w(TAG, e);
    throw new NonSuccessfulResponseCodeException("Unable to parse entity");
  }
}
 
Example 25
public TokenResponse getKeyBackupServiceToken(String authorizationToken, String enclaveName)
    throws IOException
{
  ResponseBody body = makeRequest(ClientSet.KeyBackup, authorizationToken, null, "/v1/token/" + enclaveName, "GET", null).body();

  if (body != null) {
    return JsonUtil.fromJson(body.string(), TokenResponse.class);
  } else {
    throw new NonSuccessfulResponseCodeException("Empty response!");
  }
}
 
Example 26
public DiscoveryResponse getContactDiscoveryRegisteredUsers(String authorizationToken, DiscoveryRequest request, List<String> cookies, String mrenclave)
    throws IOException
{
  ResponseBody body = makeRequest(ClientSet.ContactDiscovery, authorizationToken, cookies, "/v1/discovery/" + mrenclave, "PUT", JsonUtil.toJson(request)).body();

  if (body != null) {
    return JsonUtil.fromJson(body.string(), DiscoveryResponse.class);
  } else {
    throw new NonSuccessfulResponseCodeException("Empty response!");
  }
}
 
Example 27
public KeyBackupResponse putKbsData(String authorizationToken, KeyBackupRequest request, List<String> cookies, String mrenclave)
    throws IOException
{
  ResponseBody body = makeRequest(ClientSet.KeyBackup, authorizationToken, cookies, "/v1/backup/" + mrenclave, "PUT", JsonUtil.toJson(request)).body();

  if (body != null) {
    return JsonUtil.fromJson(body.string(), KeyBackupResponse.class);
  } else {
    throw new NonSuccessfulResponseCodeException("Empty response!");
  }
}
 
Example 28
public AttachmentV2UploadAttributes getAttachmentV2UploadAttributes() throws NonSuccessfulResponseCodeException, PushNetworkException {
  String response = makeServiceRequest(ATTACHMENT_V2_PATH, "GET", null);
  try {
    return JsonUtil.fromJson(response, AttachmentV2UploadAttributes.class);
  } catch (IOException e) {
    Log.w(TAG, e);
    throw new NonSuccessfulResponseCodeException("Unable to parse entity");
  }
}
 
Example 29
public AttachmentV3UploadAttributes getAttachmentV3UploadAttributes() throws NonSuccessfulResponseCodeException, PushNetworkException {
  String response = makeServiceRequest(ATTACHMENT_V3_PATH, "GET", null);
  try {
    return JsonUtil.fromJson(response, AttachmentV3UploadAttributes.class);
  } catch (IOException e) {
    Log.w(TAG, e);
    throw new NonSuccessfulResponseCodeException("Unable to parse entity");
  }
}
 
Example 30
public Pair<Long, byte[]> uploadAttachment(PushAttachmentData attachment, AttachmentV2UploadAttributes uploadAttributes)
    throws PushNetworkException, NonSuccessfulResponseCodeException
{
  long   id     = Long.parseLong(uploadAttributes.getAttachmentId());
  byte[] digest = uploadToCdn0(ATTACHMENT_UPLOAD_PATH, uploadAttributes.getAcl(), uploadAttributes.getKey(),
                              uploadAttributes.getPolicy(), uploadAttributes.getAlgorithm(),
                              uploadAttributes.getCredential(), uploadAttributes.getDate(),
                              uploadAttributes.getSignature(), attachment.getData(),
                              "application/octet-stream", attachment.getDataSize(),
                              attachment.getOutputStreamFactory(), attachment.getListener(),
                              attachment.getCancelationSignal());

  return new Pair<>(id, digest);
}