wip on links to files

dbus-notify
Zlatin Balevsky 2022-08-04 14:29:12 +01:00
parent bc5a977669
commit 6dfddacb8d
No known key found for this signature in database
GPG Key ID: A72832072D525E41
3 changed files with 232 additions and 0 deletions

View File

@ -0,0 +1,78 @@
package com.muwire.gui.mulinks
import com.muwire.core.InfoHash
import com.muwire.core.Persona
import com.muwire.core.SharedFile
import com.muwire.core.files.FileHasher
import net.i2p.crypto.DSAEngine
import net.i2p.data.SigningPrivateKey
import java.nio.charset.StandardCharsets
import java.nio.file.Path
class FileMuLink extends MuLink {
final long fileSize
final int pieceSizePow2
FileMuLink(Persona host, InfoHash infoHash, String name, byte[] sig, Map<String, String> query)
throws InvalidMuLinkException {
super(host, infoHash, name, sig, LinkType.FILE)
int fileSize, pieceSizePow2
try {
fileSize = Long.parseLong(query.fileSize)
pieceSizePow2 = Integer.parseInt(query.pieceSizePow2)
} catch (NumberFormatException e) {
throw new InvalidMuLinkException(e)
}
this.fileSize = fileSize
this.pieceSizePow2 = pieceSizePow2
if (fileSize <= 0 || fileSize > FileHasher.MAX_SIZE)
throw new InvalidMuLinkException("invalid size $fileSize")
if (pieceSizePow2 < FileHasher.MIN_PIECE_SIZE_POW2 || pieceSizePow2 > FileHasher.MAX_PIECE_SIZE_POW2)
throw new InvalidMuLinkException("invalid piece size $pieceSizePow2")
Path path = Path.of(name)
if (path.getNameCount() != 1)
throw new InvalidMuLinkException("name path count ${path.getNameCount()}")
}
FileMuLink(SharedFile sharedFile, Persona me, SigningPrivateKey spk) {
super(me, sharedFile.getRootInfoHash(), sharedFile.getFile().getName(),
deriveSig(sharedFile, spk),
LinkType.FILE)
fileSize = sharedFile.getCachedLength()
pieceSizePow2 = sharedFile.getPieceSize()
}
private static byte[] deriveSig(SharedFile sharedFile, SigningPrivateKey spk) {
def baos = new ByteArrayOutputStream()
def daos = new DataOutputStream(baos)
daos.write(sharedFile.getRoot())
daos.write(sharedFile.getFile().getName().getBytes(StandardCharsets.UTF_8))
daos.writeByte(LinkType.FILE.ordinal())
daos.writeLong(sharedFile.getCachedLength())
daos.writeByte(sharedFile.getPieceSize())
daos.flush()
byte [] payload = baos.toByteArray()
DSAEngine.getInstance().sign(payload, spk).getData()
}
@Override
protected void appendSignedElements(ByteArrayOutputStream baos) {
DataOutputStream daos = new DataOutputStream(baos)
daos.writeLong(fileSize)
daos.writeByte(pieceSizePow2)
daos.flush()
}
@Override
protected void addQueryElements(Map<String,String> query) {
query.fileSize = String.valueOf(fileSize)
query.pieceSizePow2 = String.valueOf(pieceSizePow2)
}
}

View File

@ -0,0 +1,15 @@
package com.muwire.gui.mulinks
class InvalidMuLinkException extends Exception {
InvalidMuLinkException(String message) {
super(message)
}
InvalidMuLinkException(String message, Throwable cause) {
super(message, cause)
}
InvalidMuLinkException(Throwable cause) {
super(cause)
}
}

View File

@ -0,0 +1,139 @@
package com.muwire.gui.mulinks
import com.muwire.core.Constants
import com.muwire.core.InfoHash
import com.muwire.core.Persona
import net.i2p.crypto.DSAEngine
import net.i2p.data.Base64
import net.i2p.data.Signature
import net.i2p.data.SigningPublicKey
import java.nio.charset.StandardCharsets
abstract class MuLink {
private static final String SCHEME = "muwire"
private static final int PORT = -1
static enum LinkType {
FILE,
COLLECTION
}
final String name
final Persona host
final InfoHash infoHash
final LinkType linkType
private final byte[] sig
protected MuLink(Persona host, InfoHash infoHash, String name, byte[] sig, LinkType linkType) {
this.host = host
this.infoHash = infoHash
this.name = name
this.sig = sig
this.linkType = linkType
}
boolean verify() {
ByteArrayOutputStream baos = new ByteArrayOutputStream()
baos.write(infoHash.getRoot())
baos.write(name.getBytes(StandardCharsets.UTF_8))
baos.write(linkType.ordinal())
appendSignedElements(baos)
byte[] payload = baos.toByteArray()
SigningPublicKey spk = host.destination.getSigningPublicKey()
Signature signature = new Signature(spk.getType(), sig)
DSAEngine.getInstance().verifySignature(signature, payload, spk)
}
protected abstract void appendSignedElements(ByteArrayOutputStream baos)
String toLink() {
def query = [:]
query.name = URLEncoder.encode(name, StandardCharsets.UTF_8)
query.sig = Base64.encode(sig)
query.type = linkType.name()
addQueryElements(query)
def kvs = []
query.each { k, v ->
kvs << "$k=$v"
}
String queryStr = kvs.join("&")
URI uri = new URI(SCHEME,
Base64.encode(infoHash.getRoot()),
host.toBase64(),
PORT,
"/",
queryStr,
null)
uri.toASCIIString()
}
protected abstract void addQueryElements(Map<String,String> query)
static MuLink parse(String url) throws InvalidMuLinkException {
try {
URI uri = new URI(url)
if (uri.getScheme() != SCHEME)
throw new InvalidMuLinkException("Unsupported scheme ${uri.getScheme()}")
if (uri.getUserInfo() == null)
throw new InvalidMuLinkException("no infohash")
InfoHash ih = new InfoHash(Base64.decode(uri.getUserInfo()))
if (uri.getHost() == null)
throw new InvalidMuLinkException("no persona")
Persona p = new Persona(new ByteArrayInputStream(Base64.decode(uri.getHost())))
Map<String,String> query = parseQuery(uri.getQuery())
if(query.name == null)
throw new InvalidMuLinkException("name missing")
String n = URLDecoder.decode(query.name, StandardCharsets.UTF_8)
if(query.sig == null)
throw new InvalidMuLinkException("no signature")
byte[] sigBytes = Base64.decode(query.sig)
if (sigBytes.length != Constants.SIG_TYPE.getSigLen())
throw new InvalidMuLinkException("invalid sig key")
if (query.type == null)
throw new InvalidMuLinkException("type missing")
LinkType linkType = LinkType.valueOf(query.type)
if (linkType == LinkType.FILE)
return new FileMuLink(p, ih, n, sigBytes, query)
throw new InvalidMuLinkException("unknown type $linkType")
} catch (InvalidMuLinkException e) {
throw e
} catch (Exception e) {
throw new InvalidMuLinkException(e)
}
}
private static Map<String, String> parseQuery(String query) throws InvalidMuLinkException {
def rv = [:]
String[] split = query.split("&")
for(String kv : split) {
int equals = kv.indexOf("=")
if (equals < 0 )
throw new InvalidMuLinkException("invalid kv $kv")
String k = kv.substring(0, equals)
String v = kv.substring(equals + 1, kv.length())
if (rv.containsKey(k))
throw new InvalidMuLinkException("duplicate key $k")
rv.k = v
}
rv
}
}