PgpDecryptionService.java

  1package eu.siacs.conversations.crypto;
  2
  3import android.app.PendingIntent;
  4import android.content.Intent;
  5
  6import org.openintents.openpgp.util.OpenPgpApi;
  7
  8import java.io.ByteArrayInputStream;
  9import java.io.ByteArrayOutputStream;
 10import java.io.FileInputStream;
 11import java.io.FileOutputStream;
 12import java.io.IOException;
 13import java.io.InputStream;
 14import java.io.OutputStream;
 15import java.net.URL;
 16import java.util.ArrayDeque;
 17import java.util.List;
 18
 19import eu.siacs.conversations.entities.Conversation;
 20import eu.siacs.conversations.entities.DownloadableFile;
 21import eu.siacs.conversations.entities.Message;
 22import eu.siacs.conversations.http.HttpConnectionManager;
 23import eu.siacs.conversations.services.XmppConnectionService;
 24
 25public class PgpDecryptionService {
 26
 27    private final XmppConnectionService mXmppConnectionService;
 28    private OpenPgpApi openPgpApi = null;
 29
 30	protected final ArrayDeque<Message> messages = new ArrayDeque();
 31	Message currentMessage;
 32    private PendingIntent pendingIntent;
 33
 34
 35    public PgpDecryptionService(XmppConnectionService service) {
 36        this.mXmppConnectionService = service;
 37    }
 38
 39	public synchronized void decrypt(final Message message) {
 40        messages.add(message);
 41		continueDecryption();
 42	}
 43
 44    public synchronized void decrypt(final List<Message> list) {
 45        for(Message message : list) {
 46            if (message.getEncryption() == Message.ENCRYPTION_PGP) {
 47                messages.add(message);
 48            }
 49        }
 50        continueDecryption();
 51    }
 52
 53	protected synchronized void decryptNext() {
 54		if (pendingIntent == null
 55                && getOpenPgpApi() != null
 56                && (currentMessage =  messages.poll()) != null) {
 57			new Thread(new Runnable() {
 58                @Override
 59                public void run() {
 60                    executeApi(currentMessage);
 61                    decryptNext();
 62                }
 63            }).start();
 64		}
 65	}
 66
 67    public synchronized void continueDecryption(boolean resetPending) {
 68        if (resetPending) {
 69            this.pendingIntent = null;
 70        }
 71        continueDecryption();
 72    }
 73
 74    public synchronized void continueDecryption() {
 75        if (currentMessage == null) {
 76            decryptNext();
 77        }
 78    }
 79
 80    private synchronized OpenPgpApi getOpenPgpApi() {
 81        if (openPgpApi == null) {
 82            this.openPgpApi = mXmppConnectionService.getOpenPgpApi();
 83        }
 84        return this.openPgpApi;
 85    }
 86
 87    private void executeApi(Message message) {
 88        Intent params = new Intent();
 89        params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
 90        if (message.getType() == Message.TYPE_TEXT) {
 91            InputStream is = new ByteArrayInputStream(message.getBody().getBytes());
 92            final OutputStream os = new ByteArrayOutputStream();
 93            Intent result = getOpenPgpApi().executeApi(params, is, os);
 94            switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
 95                case OpenPgpApi.RESULT_CODE_SUCCESS:
 96                    try {
 97                        os.flush();
 98                        message.setBody(os.toString());
 99                        message.setEncryption(Message.ENCRYPTION_DECRYPTED);
100                        final HttpConnectionManager manager = mXmppConnectionService.getHttpConnectionManager();
101                        if (message.trusted()
102                                && message.treatAsDownloadable() != Message.Decision.NEVER
103                                && manager.getAutoAcceptFileSize() > 0) {
104                            manager.createNewDownloadConnection(message);
105                        }
106                    } catch (IOException e) {
107                        message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
108                    }
109                    mXmppConnectionService.updateMessage(message);
110                    break;
111                case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
112                    messages.addFirst(message);
113                    currentMessage = null;
114                    storePendingIntent((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
115                    break;
116                case OpenPgpApi.RESULT_CODE_ERROR:
117                    message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
118                    mXmppConnectionService.updateMessage(message);
119                    break;
120            }
121        } else if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) {
122            try {
123                final DownloadableFile inputFile = mXmppConnectionService.getFileBackend().getFile(message, false);
124                final DownloadableFile outputFile = mXmppConnectionService.getFileBackend().getFile(message, true);
125                outputFile.getParentFile().mkdirs();
126                outputFile.createNewFile();
127                InputStream is = new FileInputStream(inputFile);
128                OutputStream os = new FileOutputStream(outputFile);
129                Intent result = getOpenPgpApi().executeApi(params, is, os);
130                switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
131                    case OpenPgpApi.RESULT_CODE_SUCCESS:
132                        URL url = message.getFileParams().url;
133                        mXmppConnectionService.getFileBackend().updateFileParams(message,url);
134                        message.setEncryption(Message.ENCRYPTION_DECRYPTED);
135                        inputFile.delete();
136                        mXmppConnectionService.getFileBackend().updateMediaScanner(outputFile);
137                        mXmppConnectionService.updateMessage(message);
138                        break;
139                    case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
140                        messages.addFirst(message);
141                        currentMessage = null;
142                        storePendingIntent((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
143                        break;
144                    case OpenPgpApi.RESULT_CODE_ERROR:
145                        message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
146                        mXmppConnectionService.updateMessage(message);
147                        break;
148                }
149            } catch (final IOException e) {
150                message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
151                mXmppConnectionService.updateMessage(message);
152            }
153        }
154    }
155
156    private void storePendingIntent(PendingIntent pendingIntent) {
157        this.pendingIntent = pendingIntent;
158        mXmppConnectionService.updateConversationUi();
159    }
160
161    public synchronized boolean hasPendingIntent(Conversation conversation) {
162        if (pendingIntent == null) {
163            return false;
164        } else {
165            for(Message message : messages) {
166                if (message.getConversation() == conversation) {
167                    return true;
168                }
169            }
170            return false;
171        }
172    }
173
174    public PendingIntent getPendingIntent() {
175        return pendingIntent;
176    }
177
178    public boolean isConnected() {
179        return getOpenPgpApi() != null;
180    }
181}