Objects necessary for collections

pull/53/head
Zlatin Balevsky 2020-10-30 13:57:28 +00:00
parent b973f95590
commit b9b6d760e0
No known key found for this signature in database
GPG Key ID: A72832072D525E41
4 changed files with 222 additions and 0 deletions

View File

@ -0,0 +1,117 @@
package com.muwire.core.collections
import com.muwire.core.Constants
import com.muwire.core.InfoHash
import com.muwire.core.Name
import com.muwire.core.Persona
import com.muwire.core.util.DataUtil
import net.i2p.crypto.DSAEngine
import net.i2p.data.Signature
import net.i2p.data.SigningPrivateKey
class FileCollection {
private final long timestamp
private final Persona author
private final String comment
private final byte[] sig
private volatile byte[] payload
private final Set<FileCollectionItem> files = new LinkedHashSet<>()
FileCollection(long timestamp, Persona author, String comment, Set<FileCollectionItem> files,
SigningPrivateKey spk) {
this.timestamp = timestamp;
this.author = author;
this.comment = comment
this.files = files
byte [] signablePayload = signablePayload()
Signature signature = DSAEngine.getInstance().sign(signablePayload, spk)
this.sig = signature.getData()
}
FileCollection(InputStream is) {
DataInputStream dis = new DataInputStream(is)
byte version = (byte) dis.read()
if (version != Constants.COLLECTION_VERSION)
throw new InvalidCollectionException("unsupported version $version")
int numFiles = dis.readUnsignedShort()
author = new Persona(dis)
timestamp = dis.readLong()
def commentName = new Name(dis)
comment = commentName.name
numFiles.times {
files.add(new FileCollectionItem(dis))
}
sig = new byte[Constants.SIG_TYPE.getSigLen()]
dis.readFully(sig)
if (!verify())
throw new InvalidCollectionException("invalid signature")
}
private boolean verify() {
def baos = new ByteArrayOutputStream()
def daos = new DataOutputStream(baos)
daos.writeByte(Constants.COLLECTION_VERSION)
daos.writeShort(files.size())
author.write(daos)
daos.writeLong(timestamp)
def commentName = new Name(comment)
commentName.write(daos)
files.each {
it.write(daos)
}
daos.close()
byte [] payload = baos.toByteArray()
def spk = author.destination.getSigningPublicKey()
def signature = new Signature(spk.getType(), sig)
DSAEngine.getInstance().verifySignature(signature, payload, spk)
}
private byte[] signablePayload() {
def baos = new ByteArrayOutputStream()
def daos = new DataOutputStream(baos)
daos.writeByte(Constants.COLLECTION_VERSION)
daos.writeShort(files.size())
author.write(daos)
daos.writeLong(timestamp)
def commentName = new Name(comment)
commentName.write(daos)
files.each {
it.write(daos)
}
daos.close()
baos.toByteArray()
}
public void write(OutputStream os) {
if (payload == null) {
def baos = new ByteArrayOutputStream()
def daos = new DataOutputStream(baos)
daos.write(signablePayload())
daos.write(sig)
daos.close()
payload = baos.toByteArray()
}
os.write(payload)
}
}

View File

@ -0,0 +1,77 @@
package com.muwire.core.collections
import com.muwire.core.Constants
import com.muwire.core.InfoHash
import com.muwire.core.Name
class FileCollectionItem {
private final InfoHash infoHash
private final String comment
private final File file
private volatile byte[] payload
private final List<String> pathElements = new ArrayList<>()
public FileCollectionItem(InfoHash infoHash, String comment, List<String> pathElements) {
this.infoHash = infoHash
this.comment = comment
this.pathElements = pathElements
File f = null
pathElements.each {
if (f == null) {
f = new File(it)
return
}
f = new File(f, it)
}
this.file = f
}
public FileCollectionItem(InputStream is) {
DataInputStream dis = new DataInputStream(is)
byte version = dis.readByte()
if (version != Constants.COLLECTION_ENTRY_VERSION)
throw new InvalidCollectionException("unsupported entry version $version")
byte [] hash = new byte[32]
dis.readFully(hash)
infoHash = new InfoHash(hash)
int nPathElements = dis.readUnsignedByte()
File f = null
nPathElements.times {
def element = new Name(dis)
pathElements.add(element.name)
if (f == null) {
f = new File(element.name)
return
}
f = new File(f, element.name)
}
file = f
def commentName = new Name(dis)
comment = commentName.name
}
void write(OutputStream os) {
if (payload == null) {
def baos = new ByteArrayOutputStream()
def daos = new DataOutputStream(baos)
daos.writeByte(Constants.COLLECTION_ENTRY_VERSION)
daos.write(infoHash.getRoot())
daos.writeByte((byte) pathElements.size())
pathElements.each {
def name = new Name(it)
name.write(daos)
}
def commentName = new Name(comment)
commentName.write(daos)
daos.close()
payload = baos.toByteArray()
}
os.write(payload)
}
}

View File

@ -0,0 +1,26 @@
package com.muwire.core.collections
class InvalidCollectionException extends Exception {
public InvalidCollectionException() {
super();
}
public InvalidCollectionException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public InvalidCollectionException(String message, Throwable cause) {
super(message, cause);
}
public InvalidCollectionException(String message) {
super(message);
}
public InvalidCollectionException(Throwable cause) {
super(cause);
}
}

View File

@ -8,6 +8,8 @@ public class Constants {
public static final int MAX_NICKNAME_LENGTH = 30;
public static final byte FILE_CERT_VERSION = (byte)2;
public static final int CHAT_VERSION = 1;
public static final byte COLLECTION_VERSION = (byte)1;
public static final byte COLLECTION_ENTRY_VERSION = (byte)1;
public static final SigType SIG_TYPE = SigType.EdDSA_SHA512_Ed25519;