use of org.matrix.androidsdk.rest.model.EncryptedMediaScanEncryptedBody in project matrix-android-sdk by matrix-org.
the class MediaScanRestClient method scanEncryptedFile.
/**
* Scan an encrypted file.
*
* @param encryptedMediaScanBody the encryption information required to decrypt the content before scanning it.
* @param callback on success callback containing a MediaScanResult object
*/
public void scanEncryptedFile(final EncryptedMediaScanBody encryptedMediaScanBody, final ApiCallback<MediaScanResult> callback) {
// Encrypt encryptedMediaScanBody if the server support it
getServerPublicKey(new SimpleApiCallback<String>(callback) {
@Override
public void onSuccess(String serverPublicKey) {
Call<MediaScanResult> request;
// Encrypt the data, if antivirus server supports it
if (!TextUtils.isEmpty(serverPublicKey)) {
try {
OlmPkEncryption olmPkEncryption = new OlmPkEncryption();
olmPkEncryption.setRecipientKey(serverPublicKey);
String data = JsonUtility.getCanonicalizedJsonString(encryptedMediaScanBody);
OlmPkMessage message = olmPkEncryption.encrypt(data);
EncryptedMediaScanEncryptedBody encryptedMediaScanEncryptedBody = new EncryptedMediaScanEncryptedBody();
encryptedMediaScanEncryptedBody.encryptedBodyFileInfo = new EncryptedBodyFileInfo(message);
request = mApi.scanEncrypted(encryptedMediaScanEncryptedBody);
} catch (OlmException e) {
// should not happen. Send the error to the caller
request = null;
callback.onUnexpectedError(e);
}
} else {
// No public key on this server, do not encrypt data
request = mApi.scanEncrypted(encryptedMediaScanBody);
}
if (request != null) {
request.enqueue(new RestAdapterCallback<>("scanEncryptedFile", null, new SimpleApiCallback<MediaScanResult>(callback) {
@Override
public void onSuccess(MediaScanResult scanResult) {
callback.onSuccess(scanResult);
}
@Override
public void onMatrixError(MatrixError e) {
// Check whether the provided encrypted_body could not be decrypted.
if (e.mStatus == HttpURLConnection.HTTP_FORBIDDEN) {
MediaScanError mcsError;
try {
mcsError = JsonUtils.getGson(false).fromJson(e.mErrorBodyAsString, MediaScanError.class);
} catch (Exception exc) {
mcsError = null;
}
if (mcsError != null && MediaScanError.MCS_BAD_DECRYPTION.equals(mcsError.reason)) {
// The client should request again the public key of the server.
resetServerPublicKey();
}
}
super.onMatrixError(e);
}
}, null));
}
}
});
}
use of org.matrix.androidsdk.rest.model.EncryptedMediaScanEncryptedBody in project matrix-android-sdk by matrix-org.
the class MXMediaDownloadWorkerTask method doInBackground.
/**
* Download and decode media in background.
*
* @param params
* @return JsonElement if an error occurs
*/
@Override
protected JsonElement doInBackground(Void... params) {
JsonElement jsonElementResult = null;
MatrixError defaultError = new MatrixError();
defaultError.errcode = MatrixError.UNKNOWN;
try {
URL url = new URL(mUrl);
Log.d(LOG_TAG, "MXMediaDownloadWorkerTask " + this + " starts");
mDownloadStats = new IMXMediaDownloadListener.DownloadStats();
// don't known yet
mDownloadStats.mEstimatedRemainingTime = -1;
InputStream stream = null;
int filelen = -1;
HttpURLConnection connection = null;
try {
Proxy proxyConfig = mHsConfig.getProxyConfig();
if (proxyConfig == null) {
proxyConfig = Proxy.NO_PROXY;
}
connection = (HttpURLConnection) url.openConnection(proxyConfig);
if (RestClient.getUserAgent() != null) {
connection.setRequestProperty("User-Agent", RestClient.getUserAgent());
}
if (mHsConfig != null && connection instanceof HttpsURLConnection) {
// Add SSL Socket factory.
HttpsURLConnection sslConn = (HttpsURLConnection) connection;
try {
Pair<SSLSocketFactory, X509TrustManager> pair = CertUtil.newPinnedSSLSocketFactory(mHsConfig);
sslConn.setSSLSocketFactory(pair.first);
sslConn.setHostnameVerifier(CertUtil.newHostnameVerifier(mHsConfig));
} catch (Exception e) {
Log.e(LOG_TAG, "doInBackground SSL exception " + e.getMessage(), e);
}
}
// add a timeout to avoid infinite loading display.
float scale = (null != mNetworkConnectivityReceiver) ? mNetworkConnectivityReceiver.getTimeoutScale() : 1.0f;
connection.setReadTimeout((int) (DOWNLOAD_TIME_OUT * scale));
if (mIsAvScannerEnabled && null != mEncryptedFileInfo) {
// POST the encryption info to let the av scanner decrypt and scan the content.
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setDoOutput(true);
connection.setUseCaches(false);
EncryptedMediaScanBody encryptedMediaScanBody = new EncryptedMediaScanBody();
encryptedMediaScanBody.encryptedFileInfo = mEncryptedFileInfo;
String data = JsonUtility.getCanonicalizedJsonString(encryptedMediaScanBody);
// Encrypt the data, if antivirus server supports it
String publicServerKey = getAntivirusServerPublicKey();
if (publicServerKey == null) {
// Error
throw new Exception("Unable to get public key");
} else if (!TextUtils.isEmpty(publicServerKey)) {
OlmPkEncryption olmPkEncryption = new OlmPkEncryption();
olmPkEncryption.setRecipientKey(publicServerKey);
OlmPkMessage message = olmPkEncryption.encrypt(data);
EncryptedMediaScanEncryptedBody encryptedMediaScanEncryptedBody = new EncryptedMediaScanEncryptedBody();
encryptedMediaScanEncryptedBody.encryptedBodyFileInfo = new EncryptedBodyFileInfo(message);
data = JsonUtility.getCanonicalizedJsonString(encryptedMediaScanEncryptedBody);
}
// Else: no public key on this server, do not encrypt data
OutputStream outputStream = connection.getOutputStream();
try {
outputStream.write(data.getBytes("UTF-8"));
} catch (Exception e) {
Log.e(LOG_TAG, "doInBackground Failed to serialize encryption info " + e.getMessage(), e);
} finally {
outputStream.close();
}
}
filelen = connection.getContentLength();
stream = connection.getInputStream();
} catch (Exception e) {
Log.e(LOG_TAG, "bitmapForURL : fail to open the connection " + e.getMessage(), e);
defaultError.error = e.getLocalizedMessage();
// In case of 403, revert the key
if (connection.getResponseCode() == HttpURLConnection.HTTP_FORBIDDEN && mMediaScanRestClient != null) {
mMediaScanRestClient.resetServerPublicKey();
}
InputStream errorStream = connection.getErrorStream();
if (null != errorStream) {
try {
BufferedReader streamReader = new BufferedReader(new InputStreamReader(errorStream, "UTF-8"));
StringBuilder responseStrBuilder = new StringBuilder();
String inputStr;
while ((inputStr = streamReader.readLine()) != null) {
responseStrBuilder.append(inputStr);
}
jsonElementResult = new JsonParser().parse(responseStrBuilder.toString());
} catch (Exception ee) {
Log.e(LOG_TAG, "bitmapForURL : Error parsing error " + ee.getMessage(), ee);
}
}
// privacy
// Log.d(LOG_TAG, "MediaWorkerTask " + mUrl + " does not exist");
Log.d(LOG_TAG, "MediaWorkerTask an url does not exist");
// (because the same url is used for all encrypted media when the av scanner is enabled).
if (!mIsAvScannerEnabled || null == mEncryptedFileInfo) {
synchronized (sUnreachableUrls) {
sUnreachableUrls.add(mUrl);
}
}
}
dispatchDownloadStart();
// failed to open the remote stream without having exception
if ((null == stream) && (null == jsonElementResult)) {
jsonElementResult = new JsonParser().parse("Cannot open " + mUrl);
// (because the same url is used for all encrypted media when the av scanner is enabled).
if (!mIsAvScannerEnabled || null == mEncryptedFileInfo) {
synchronized (sUnreachableUrls) {
sUnreachableUrls.add(mUrl);
}
}
}
// test if the download has not been cancelled
if (!isDownloadCancelled() && (null == jsonElementResult)) {
final long startDownloadTime = System.currentTimeMillis();
String filename = buildFileName(mDownloadId, mMimeType) + ".tmp";
FileOutputStream fos = new FileOutputStream(new File(mDirectoryFile, filename));
mDownloadStats.mDownloadId = mDownloadId;
mDownloadStats.mProgress = 0;
mDownloadStats.mDownloadedSize = 0;
mDownloadStats.mFileSize = filelen;
mDownloadStats.mElapsedTime = 0;
mDownloadStats.mEstimatedRemainingTime = -1;
mDownloadStats.mBitRate = 0;
// Publish progress every 100ms
final Timer refreshTimer = new Timer();
refreshTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if (!mIsDone) {
updateAndPublishProgress(startDownloadTime);
}
}
}, new Date(), 100);
try {
byte[] buf = new byte[DOWNLOAD_BUFFER_READ_SIZE];
int len;
while (!isDownloadCancelled() && (len = stream.read(buf)) != -1) {
fos.write(buf, 0, len);
mDownloadStats.mDownloadedSize += len;
}
if (!isDownloadCancelled()) {
mDownloadStats.mProgress = 100;
}
} catch (OutOfMemoryError outOfMemoryError) {
Log.e(LOG_TAG, "doInBackground: out of memory", outOfMemoryError);
defaultError.error = outOfMemoryError.getLocalizedMessage();
} catch (Exception e) {
Log.e(LOG_TAG, "doInBackground fail to read image " + e.getMessage(), e);
defaultError.error = e.getLocalizedMessage();
}
mIsDone = true;
close(stream);
fos.flush();
fos.close();
refreshTimer.cancel();
if ((null != connection) && (connection instanceof HttpsURLConnection)) {
connection.disconnect();
}
// the file has been successfully downloaded
if (mDownloadStats.mProgress == 100) {
try {
File originalFile = new File(mDirectoryFile, filename);
String newFileName = buildFileName(mDownloadId, mMimeType);
File newFile = new File(mDirectoryFile, newFileName);
if (newFile.exists()) {
// Or you could throw here.
mApplicationContext.deleteFile(newFileName);
}
originalFile.renameTo(newFile);
} catch (Exception e) {
Log.e(LOG_TAG, "doInBackground : renaming error " + e.getMessage(), e);
defaultError.error = e.getLocalizedMessage();
}
}
}
if (mDownloadStats.mProgress == 100) {
Log.d(LOG_TAG, "The download " + this + " is done.");
} else {
if (null != jsonElementResult) {
Log.d(LOG_TAG, "The download " + this + " failed : mErrorAsJsonElement " + jsonElementResult.toString());
} else {
Log.d(LOG_TAG, "The download " + this + " failed.");
}
}
} catch (Exception e) {
Log.e(LOG_TAG, "Unable to download media " + this, e);
defaultError.error = e.getMessage();
}
// build a JSON from the error
if (!TextUtils.isEmpty(defaultError.error)) {
jsonElementResult = JsonUtils.getGson(false).toJsonTree(defaultError);
}
// remove the task from the loading one
synchronized (sPendingDownloadById) {
sPendingDownloadById.remove(mDownloadId);
}
return jsonElementResult;
}
Aggregations