EIP5169 files from IPFS are intrinsically signed (#2792)

pull/2796/head
James Brown 2 years ago committed by GitHub
parent a14cb14aba
commit 5746c1e1dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 67
      app/src/main/java/com/alphawallet/app/service/AssetDefinitionService.java

@ -130,6 +130,9 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
private static final String ASSET_DEFINITION_DB = "ASSET-db.realm";
private static final String BUNDLED_SCRIPT = "bundled";
private static final long CHECK_TX_LOGS_INTERVAL = 20;
private static final String EIP5169_ISSUER = "EIP5169-IPFS";
private static final String EIP5169_CERTIFIER = "Smart Token Labs";
private static final String EIP5169_KEY_OWNER = "Contract Owner"; //TODO Source this from the contract via owner()
private final Context context;
private final OkHttpClient okHttpClient;
@ -928,7 +931,7 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
final TokenDefinition td = parseFile(tsf.getInputStream());
List<ContractLocator> originContracts = getOriginContracts(td);
//remove all old definitions & certificates
deleteScriptEntriesFromRealm(originContracts, isDebugOverride);
deleteScriptEntriesFromRealm(originContracts, isDebugOverride, tsf.calcMD5());
cachedDefinition = null;
return cacheSignature(tsf)
.map(contracts -> fileLoadComplete(originContracts, tsf, td));
@ -941,7 +944,7 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
return Single.fromCallable(TokenDefinition::new);
}
private void deleteScriptEntriesFromRealm(List<ContractLocator> origins, boolean isDebug)
private void deleteScriptEntriesFromRealm(List<ContractLocator> origins, boolean isDebug, String newFileHash)
{
try (Realm realm = realmManager.getRealmInstance(ASSET_DEFINITION_DB))
{
@ -958,7 +961,7 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
RealmCertificateData realmCert = r.where(RealmCertificateData.class)
.equalTo("instanceKey", realmData.getFileHash())
.findFirst();
if (realmCert != null) realmCert.deleteFromRealm();
if (realmCert != null && !realmData.getFileHash().equals(newFileHash)) realmCert.deleteFromRealm(); //don't delete cert if new cert will overwrite it
deleteEventDataForScript(realmData);
realmData.deleteFromRealm();
}
@ -975,7 +978,7 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
if (!TextUtils.isEmpty(uri)) updateFlag.postValue(true);
return uri; })
.map(uri -> downloadScript(uri, 0))
.map(xmlBody -> storeFile(token.tokenInfo.address, xmlBody));
.map(dlResponse -> storeFile(token.tokenInfo.address, dlResponse));
}
private Single<File> tryServerIfRequired(File contractScript, String address)
@ -1025,10 +1028,10 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
"/" +
address;
String xmlBody = downloadScript(sb, fileTime);
if (!TextUtils.isEmpty(xmlBody))
Pair<String, Boolean> downloadResponse = downloadScript(sb, fileTime);
if (!TextUtils.isEmpty(downloadResponse.first))
{
result = storeFile(address, xmlBody);
result = storeFile(address, downloadResponse);
}
assetChecked.put(address, System.currentTimeMillis());
@ -1037,9 +1040,10 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
});
}
private String downloadScript(String Uri, long currentFileTime) throws PackageManager.NameNotFoundException
private Pair<String, Boolean> downloadScript(String Uri, long currentFileTime) throws PackageManager.NameNotFoundException
{
if (TextUtils.isEmpty(Uri)) return "";
boolean isIPFS = false;
if (TextUtils.isEmpty(Uri)) return new Pair<>("", false);
SimpleDateFormat format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss 'GMT'", Locale.ENGLISH);
format.setTimeZone(TimeZone.getTimeZone("UTC"));
String dateFormat = format.format(new Date(currentFileTime));
@ -1058,7 +1062,7 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
.url(Uri)
.get();
if (!Uri.toLowerCase().contains("ipfs"))
if (!Uri.toLowerCase().contains("ipfs.io"))
{
bld.addHeader("Accept", "text/xml; charset=UTF-8")
.addHeader("X-Client-Name", "AlphaWallet")
@ -1067,6 +1071,10 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
.addHeader("X-Platform-Version", OSVersion)
.addHeader("If-Modified-Since", dateFormat);
}
else
{
isIPFS = true;
}
Request request = bld.build();
@ -1079,7 +1087,7 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
case HttpURLConnection.HTTP_NOT_MODIFIED:
break;
case HttpURLConnection.HTTP_OK:
return response.body().string();
return new Pair<>(response.body().string(), isIPFS);
}
}
catch (Exception e)
@ -1087,7 +1095,7 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
Timber.e(e);
}
return "";
return new Pair<>("", false);
}
private boolean definitionIsOutOfDate(TokenDefinition td)
@ -1586,15 +1594,18 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
{
try (Realm realm = realmManager.getRealmInstance(ASSET_DEFINITION_DB))
{
realm.executeTransactionAsync(r -> {
realm.executeTransaction(r -> {
//if signature present, then just update
RealmCertificateData realmData = r.where(RealmCertificateData.class)
.equalTo("instanceKey", hash)
.findFirst();
if (realmData == null)
{
realmData = r.createObject(RealmCertificateData.class, hash);
}
realmData.setFromSig(sig);
r.insertOrUpdate(realmData);
});
}
}
@ -1628,6 +1639,19 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
return sig;
}
private XMLDsigDescriptor IPFSSigDescriptor()
{
XMLDsigDescriptor sig = new XMLDsigDescriptor();
sig.issuer = EIP5169_ISSUER;
sig.certificateName = EIP5169_CERTIFIER;
sig.keyName = EIP5169_KEY_OWNER;
sig.keyType = "ECDSA";
sig.result = "Pass";
sig.subject = "";
sig.type = SigReturnType.SIGNATURE_PASS;
return sig;
}
/**
* Use internal directory to store contracts fetched from the server
* @param address
@ -1635,9 +1659,9 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
* @return
* @throws
*/
private File storeFile(String address, String result) throws IOException
private File storeFile(String address, Pair<String, Boolean> result) throws IOException
{
if (result == null || result.length() < 10) return new File("");
if (result.first == null || result.first.length() < 10) return new File("");
String fName = address + ".xml";
@ -1646,10 +1670,19 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
FileOutputStream fos = new FileOutputStream(file);
OutputStream os = new BufferedOutputStream(fos);
os.write(result.getBytes());
os.write(result.first.getBytes());
fos.flush();
os.close();
fos.close();
//handle signature for IPFS
if (result.second)
{
TokenScriptFile tsf = new TokenScriptFile(context, file.getAbsolutePath());
String hash = tsf.calcMD5();
storeCertificateData(hash, IPFSSigDescriptor());
}
return file;
}
@ -1990,7 +2023,7 @@ public class AssetDefinitionService implements ParseResult, AttributeInterface
{
String hash = tsf.calcMD5();
XMLDsigDescriptor sig = getCertificateFromRealm(hash);
if (sig == null || (sig.result != null && sig.result.equals("fail")))
if (sig == null || (sig.result != null && sig.result.equalsIgnoreCase("fail")))
{
sig = alphaWalletService.checkTokenScriptSignature(tsf);
tsf.determineSignatureType(sig);

Loading…
Cancel
Save