From dbe909945f52649f412183f685b6ebb793c9ae03 Mon Sep 17 00:00:00 2001 From: Zlatin Balevsky Date: Tue, 22 Feb 2022 17:01:59 +0000 Subject: [PATCH] lint the json on update server startup --- .../com/muwire/update/UpdateServer.groovy | 62 +++++++++++++++++-- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/update-server/src/main/groovy/com/muwire/update/UpdateServer.groovy b/update-server/src/main/groovy/com/muwire/update/UpdateServer.groovy index e402c979..750baf23 100644 --- a/update-server/src/main/groovy/com/muwire/update/UpdateServer.groovy +++ b/update-server/src/main/groovy/com/muwire/update/UpdateServer.groovy @@ -1,5 +1,8 @@ package com.muwire.update +import net.i2p.data.Base64 +import net.i2p.util.VersionComparator + import java.util.logging.Level import groovy.json.JsonSlurper @@ -42,6 +45,9 @@ class UpdateServer { System.exit(1) } + byte [] json = loadJson(update) + log.info("update.json sanity check passed") + Properties props = System.getProperties().clone() props["inbound.nickname"] = "MuWire UpdateServer" def i2pPropsFile = new File(home, "i2p.properties") @@ -51,19 +57,67 @@ class UpdateServer { session = i2pClient.createSession(new FileInputStream(keyFile), props) myDest = session.getMyDestination() - session.addMuxedSessionListener(new Listener(update), I2PSession.PROTO_DATAGRAM, I2PSession.PORT_ANY) + session.addMuxedSessionListener(new Listener(json), I2PSession.PROTO_DATAGRAM, I2PSession.PORT_ANY) session.connect() log.info("Connected, going to sleep") while(true) Thread.sleep(Integer.MAX_VALUE) } + + /** also performs sanity checks */ + private static byte[] loadJson(File file) { + // 1. Check if valid json + JsonSlurper slurper = new JsonSlurper() + def parsed = slurper.parse(file) + + // 2. check if version parses + if (VersionComparator.comp("0.0.0", (String)parsed.version) >= 0) + throw new Exception("version invalid ${parsed.version}") + + // 3. check string fields + ["signer","text"].each { checkString(parsed[it])} + + // 4. check infohashes + ["infoHash","exe","mac","appimage","appimage-aarch64"].each {checkInfoHash(parsed[it])} + + // 5. check beta + if (parsed.beta != null) { + + // 1. Version must be an integer + Integer.parseInt(parsed.beta.version) + + // 2. text fields + ["signer","text"].each {checkString(parsed.beta[it])} + + // 3. infohashes + ["exe","appimage","mac"].each { + if (parsed.beta[it] != null) + checkInfoHash(parsed.beta[it]) + } + } + + // if we got here we're good + file.bytes + } + + private static void checkString(def obj) { + if (!(obj instanceof String)) + throw new Exception("object not a string") + } + + private static void checkInfoHash(def obj) { + String s = (String) obj + byte [] decoded = Base64.decode(s) + if (decoded.length != 32) + throw new Exception("invalid infohash") + } static class Listener implements I2PSessionMuxedListener { - private final File json + private final byte[] json private final def slurper = new JsonSlurper() - Listener(File json) { + Listener(byte[] json) { this.json = json } @@ -87,7 +141,7 @@ class UpdateServer { log.info("Got an update ping from "+sender.toBase32() + " reported version "+payload?.myVersion) def maker = new I2PDatagramMaker(session) - def response = maker.makeI2PDatagram(json.bytes) + def response = maker.makeI2PDatagram(json) session.sendMessage(sender, response, I2PSession.PROTO_DATAGRAM, 0, 2) } catch (Exception e) { log.log(Level.WARNING, "exception responding to update request",e)