mirror of https://github.com/zlatinb/muwire
Objects necessary for collections
parent
b973f95590
commit
b9b6d760e0
|
@ -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)
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue