mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
188 lines
6.6 KiB
Java
188 lines
6.6 KiB
Java
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
package org.mozilla.gecko.sync.middleware;
|
|
|
|
import java.io.UnsupportedEncodingException;
|
|
import java.util.concurrent.ExecutorService;
|
|
|
|
import org.mozilla.gecko.sync.CryptoRecord;
|
|
import org.mozilla.gecko.sync.crypto.CryptoException;
|
|
import org.mozilla.gecko.sync.crypto.KeyBundle;
|
|
import org.mozilla.gecko.sync.repositories.InactiveSessionException;
|
|
import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
|
|
import org.mozilla.gecko.sync.repositories.RecordFactory;
|
|
import org.mozilla.gecko.sync.repositories.RepositorySession;
|
|
import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
|
|
import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
|
|
import org.mozilla.gecko.sync.repositories.domain.Record;
|
|
|
|
/**
|
|
* It's a RepositorySession that accepts Records as input, producing CryptoRecords
|
|
* for submission to a remote service.
|
|
* Takes a RecordFactory as a parameter. This is in charge of taking decrypted CryptoRecords
|
|
* as input and producing some expected kind of Record as output for local use.
|
|
*
|
|
*
|
|
|
|
|
|
|
|
+------------------------------------+
|
|
| Server11RepositorySession |
|
|
+-------------------------+----------+
|
|
^ |
|
|
| |
|
|
Encrypted CryptoRecords
|
|
| |
|
|
| v
|
|
+---------+--------------------------+
|
|
| Crypto5MiddlewareRepositorySession |
|
|
+------------------------------------+
|
|
^ |
|
|
| | Decrypted CryptoRecords
|
|
| |
|
|
| +---------------+
|
|
| | RecordFactory |
|
|
| +--+------------+
|
|
| |
|
|
Local Record instances
|
|
| |
|
|
| v
|
|
+---------+--------------------------+
|
|
| Local RepositorySession instance |
|
|
+------------------------------------+
|
|
|
|
|
|
* @author rnewman
|
|
*
|
|
*/
|
|
public class Crypto5MiddlewareRepositorySession extends MiddlewareRepositorySession {
|
|
private KeyBundle keyBundle;
|
|
private RecordFactory recordFactory;
|
|
|
|
public Crypto5MiddlewareRepositorySession(RepositorySession session, Crypto5MiddlewareRepository repository, RecordFactory recordFactory) {
|
|
super(session, repository);
|
|
this.keyBundle = repository.keyBundle;
|
|
this.recordFactory = recordFactory;
|
|
}
|
|
|
|
public class DecryptingTransformingFetchDelegate implements RepositorySessionFetchRecordsDelegate {
|
|
private RepositorySessionFetchRecordsDelegate next;
|
|
private KeyBundle keyBundle;
|
|
private RecordFactory recordFactory;
|
|
|
|
DecryptingTransformingFetchDelegate(RepositorySessionFetchRecordsDelegate next, KeyBundle bundle, RecordFactory recordFactory) {
|
|
this.next = next;
|
|
this.keyBundle = bundle;
|
|
this.recordFactory = recordFactory;
|
|
}
|
|
|
|
@Override
|
|
public void onFetchFailed(Exception ex, Record record) {
|
|
next.onFetchFailed(ex, record);
|
|
}
|
|
|
|
@Override
|
|
public void onFetchedRecord(Record record) {
|
|
CryptoRecord r;
|
|
try {
|
|
r = (CryptoRecord) record;
|
|
} catch (ClassCastException e) {
|
|
next.onFetchFailed(e, record);
|
|
return;
|
|
}
|
|
r.keyBundle = keyBundle;
|
|
try {
|
|
r.decrypt();
|
|
} catch (Exception e) {
|
|
next.onFetchFailed(e, r);
|
|
return;
|
|
}
|
|
Record transformed;
|
|
try {
|
|
transformed = this.recordFactory.createRecord(r);
|
|
} catch (Exception e) {
|
|
next.onFetchFailed(e, r);
|
|
return;
|
|
}
|
|
next.onFetchedRecord(transformed);
|
|
}
|
|
|
|
@Override
|
|
public void onFetchSucceeded(Record[] records, long fetchEnd) {
|
|
for (Record record : records) {
|
|
try {
|
|
this.onFetchedRecord(record);
|
|
} catch (Exception e) {
|
|
this.onFetchFailed(e, record);
|
|
}
|
|
}
|
|
this.onFetchCompleted(fetchEnd);
|
|
}
|
|
|
|
@Override
|
|
public void onFetchCompleted(final long fetchEnd) {
|
|
next.onFetchCompleted(fetchEnd);
|
|
}
|
|
|
|
@Override
|
|
public RepositorySessionFetchRecordsDelegate deferredFetchDelegate(ExecutorService executor) {
|
|
// Synchronously perform *our* work, passing through appropriately.
|
|
RepositorySessionFetchRecordsDelegate deferredNext = next.deferredFetchDelegate(executor);
|
|
return new DecryptingTransformingFetchDelegate(deferredNext, keyBundle, recordFactory);
|
|
}
|
|
}
|
|
|
|
private DecryptingTransformingFetchDelegate makeUnwrappingDelegate(RepositorySessionFetchRecordsDelegate inner) {
|
|
if (inner == null) {
|
|
throw new IllegalArgumentException("Inner delegate cannot be null!");
|
|
}
|
|
return new DecryptingTransformingFetchDelegate(inner, this.keyBundle, this.recordFactory);
|
|
}
|
|
|
|
@Override
|
|
public void fetchSince(long timestamp,
|
|
RepositorySessionFetchRecordsDelegate delegate) {
|
|
inner.fetchSince(timestamp, makeUnwrappingDelegate(delegate));
|
|
}
|
|
|
|
@Override
|
|
public void fetch(String[] guids,
|
|
RepositorySessionFetchRecordsDelegate delegate) throws InactiveSessionException {
|
|
inner.fetch(guids, makeUnwrappingDelegate(delegate));
|
|
}
|
|
|
|
@Override
|
|
public void fetchAll(RepositorySessionFetchRecordsDelegate delegate) {
|
|
inner.fetchAll(makeUnwrappingDelegate(delegate));
|
|
}
|
|
|
|
@Override
|
|
public void setStoreDelegate(RepositorySessionStoreDelegate delegate) {
|
|
// TODO: it remains to be seen how this will work.
|
|
inner.setStoreDelegate(delegate);
|
|
this.delegate = delegate; // So we can handle errors without involving inner.
|
|
}
|
|
|
|
@Override
|
|
public void store(Record record) throws NoStoreDelegateException {
|
|
if (delegate == null) {
|
|
throw new NoStoreDelegateException();
|
|
}
|
|
CryptoRecord rec = record.getEnvelope();
|
|
rec.keyBundle = this.keyBundle;
|
|
try {
|
|
rec.encrypt();
|
|
} catch (UnsupportedEncodingException e) {
|
|
delegate.onRecordStoreFailed(e);
|
|
return;
|
|
} catch (CryptoException e) {
|
|
delegate.onRecordStoreFailed(e);
|
|
return;
|
|
}
|
|
// Allow the inner session to do delegate handling.
|
|
inner.store(rec);
|
|
}
|
|
}
|