Search in sources :

Example 1 with ParsingException

use of org.opendatakit.briefcase.model.ParsingException in project briefcase by opendatakit.

the class BadXMLFixer method fixBadXML.

public static Document fixBadXML(File xmlFile) throws CannotFixXMLException {
    log.info("Trying to fix the submission {} ", xmlFile.getAbsolutePath());
    try {
        String originalXML = FileUtils.readFileToString(xmlFile, ENCODING);
        String fixedXML = fixXML(originalXML);
        File tempFile = File.createTempFile(xmlFile.getName(), ".fixed.xml");
        FileUtils.writeStringToFile(tempFile, fixedXML, ENCODING);
        return XmlManipulationUtils.parseXml(tempFile);
    } catch (IOException | ParsingException | FileSystemException e) {
        log.error("Cannot fix xml", e);
        throw new CannotFixXMLException("Cannot fix xml", e);
    }
}
Also used : CannotFixXMLException(org.opendatakit.briefcase.model.CannotFixXMLException) FileSystemException(org.opendatakit.briefcase.model.FileSystemException) ParsingException(org.opendatakit.briefcase.model.ParsingException) IOException(java.io.IOException) File(java.io.File)

Example 2 with ParsingException

use of org.opendatakit.briefcase.model.ParsingException in project briefcase by opendatakit.

the class ExportToCsv method processInstance.

private boolean processInstance(File instanceDir) {
    File submission = new File(instanceDir, "submission.xml");
    if (!submission.exists() || !submission.isFile()) {
        EventBus.publish(new ExportProgressEvent("Submission not found for instance directory: " + instanceDir.getPath(), briefcaseLfd));
        return false;
    }
    processedInstances++;
    EventBus.publish(new ExportProgressEvent("Processing instance: " + instanceDir.getName(), briefcaseLfd));
    EventBus.publish(new ExportProgressPercentageEvent((processedInstances * 100.0) / totalInstances, briefcaseLfd));
    // If we are encrypted, be sure the temporary directory
    // that will hold the unencrypted files is created.
    // If we aren't encrypted, the temporary directory
    // is the same as the instance directory.
    File unEncryptedDir;
    if (briefcaseLfd.isFileEncryptedForm()) {
        // create the temp directory that will hold the unencrypted
        // files. Do this in the outputDir so that the briefcase storage location
        // can be a read-only network mount. issue 676.
        Path path;
        try {
            path = Files.createTempDirectory(Paths.get(outputDir.toURI()), ".temp");
        } catch (IOException e) {
            String msg = "Unable to create temp directory.";
            log.error(msg, e);
            EventBus.publish(new ExportProgressEvent(msg + " Cause : " + e.toString(), briefcaseLfd));
            return false;
        }
        unEncryptedDir = path.toFile();
    } else {
        unEncryptedDir = instanceDir;
    }
    // parse the xml document (this is the manifest if encrypted)...
    Document doc;
    boolean isValidated = false;
    try {
        doc = XmlManipulationUtils.parseXml(submission);
    } catch (ParsingException | FileSystemException e) {
        log.error("Error parsing submission", e);
        EventBus.publish(new ExportProgressEvent(("Error parsing submission " + instanceDir.getName()) + " Cause: " + e.toString(), briefcaseLfd));
        return false;
    }
    String submissionDate = null;
    // extract the submissionDate, if present, from the attributes
    // of the root element of the submission or submission manifest (if encrypted).
    submissionDate = doc.getRootElement().getAttributeValue(null, "submissionDate");
    if (submissionDate == null || submissionDate.length() == 0) {
        submissionDate = null;
    } else {
        Date theDate = WebUtils.parseDate(submissionDate);
        DateFormat formatter = DateFormat.getDateTimeInstance();
        submissionDate = formatter.format(theDate);
        // just return true to skip records out of range
        if (startDate != null && theDate.before(startDate)) {
            log.info("Submission date is before specified, skipping: " + instanceDir.getName());
            return true;
        }
        if (endDate != null && theDate.after(endDate)) {
            log.info("Submission date is after specified, skipping: " + instanceDir.getName());
            return true;
        }
        // don't export records without dates if either date is set
        if ((startDate != null || endDate != null) && submissionDate == null) {
            log.info("No submission date found, skipping: " + instanceDir.getName());
            return true;
        }
    }
    // failure.
    try {
        if (briefcaseLfd.isFileEncryptedForm()) {
            // NOTE: this changes the value of 'doc'
            try {
                FileSystemUtils.DecryptOutcome outcome = FileSystemUtils.decryptAndValidateSubmission(doc, briefcaseLfd.getPrivateKey(), instanceDir, unEncryptedDir);
                doc = outcome.submission;
                isValidated = outcome.isValidated;
            } catch (ParsingException | CryptoException | FileSystemException e) {
                // Was unable to parse file or decrypt file or a file system error occurred
                // Hence skip this instance
                EventBus.publish(new ExportProgressEvent("Error decrypting submission " + instanceDir.getName() + " Cause: " + e.toString() + " skipping....", briefcaseLfd));
                log.info("Error decrypting submission " + instanceDir.getName() + " Cause: " + e.toString());
                // update total number of files skipped
                totalFilesSkipped++;
                return true;
            }
        }
        String instanceId = null;
        String base64EncryptedFieldKey = null;
        // find an instanceId to use...
        try {
            FormInstanceMetadata sim = XmlManipulationUtils.getFormInstanceMetadata(doc.getRootElement());
            instanceId = sim.instanceId;
            base64EncryptedFieldKey = sim.base64EncryptedFieldKey;
        } catch (ParsingException e) {
            log.error("Could not extract metadata from submission", e);
            EventBus.publish(new ExportProgressEvent("Could not extract metadata from submission " + submission.getAbsolutePath(), briefcaseLfd));
            return false;
        }
        if (instanceId == null || instanceId.length() == 0) {
            // if we have no instanceID, and there isn't any in the file,
            // use the checksum as the id.
            // NOTE: encrypted submissions always have instanceIDs.
            // This is for legacy non-OpenRosa forms.
            long checksum;
            try {
                checksum = FileUtils.checksumCRC32(submission);
            } catch (IOException e1) {
                String msg = "Failed during computing of crc";
                log.error(msg, e1);
                EventBus.publish(new ExportProgressEvent(msg + ": " + e1.getMessage(), briefcaseLfd));
                return false;
            }
            instanceId = "crc32:" + Long.toString(checksum);
        }
        if (terminationFuture.isCancelled()) {
            EventBus.publish(new ExportProgressEvent("Aborted", briefcaseLfd));
            return false;
        }
        EncryptionInformation ei = null;
        if (base64EncryptedFieldKey != null) {
            try {
                ei = new EncryptionInformation(base64EncryptedFieldKey, instanceId, briefcaseLfd.getPrivateKey());
            } catch (CryptoException e) {
                log.error("Error establishing field decryption", e);
                EventBus.publish(new ExportProgressEvent("Error establishing field decryption for submission " + instanceDir.getName() + " Cause: " + e.toString(), briefcaseLfd));
                return false;
            }
        }
        // emit the csv record...
        try {
            OutputStreamWriter osw = fileMap.get(briefcaseLfd.getSubmissionElement());
            emitString(osw, true, submissionDate);
            emitSubmissionCsv(osw, ei, doc.getRootElement(), briefcaseLfd.getSubmissionElement(), briefcaseLfd.getSubmissionElement(), false, instanceId, unEncryptedDir);
            emitString(osw, false, instanceId);
            if (briefcaseLfd.isFileEncryptedForm()) {
                emitString(osw, false, Boolean.toString(isValidated));
                if (!isValidated) {
                    EventBus.publish(new ExportProgressEvent("Decrypted submission " + instanceDir.getName() + " may be missing attachments and could not be validated.", briefcaseLfd));
                }
            }
            osw.append("\n");
            return true;
        } catch (IOException e) {
            String msg = "Failed writing csv";
            log.error(msg, e);
            EventBus.publish(new ExportProgressEvent(msg + ": " + e.getMessage(), briefcaseLfd));
            return false;
        }
    } finally {
        if (briefcaseLfd.isFileEncryptedForm()) {
            // destroy the temp directory and its contents...
            try {
                FileUtils.deleteDirectory(unEncryptedDir);
            } catch (IOException e) {
                String msg = "Unable to remove decrypted files";
                log.error(msg, e);
                EventBus.publish(new ExportProgressEvent(msg + ": " + e.getMessage(), briefcaseLfd));
                return false;
            }
        }
    }
}
Also used : Path(java.nio.file.Path) FormInstanceMetadata(org.opendatakit.briefcase.util.XmlManipulationUtils.FormInstanceMetadata) IOException(java.io.IOException) Document(org.kxml2.kdom.Document) ExportProgressEvent(org.opendatakit.briefcase.model.ExportProgressEvent) Date(java.util.Date) LocalDate(java.time.LocalDate) FileSystemException(org.opendatakit.briefcase.model.FileSystemException) ParsingException(org.opendatakit.briefcase.model.ParsingException) DateFormat(java.text.DateFormat) ExportProgressPercentageEvent(org.opendatakit.briefcase.model.ExportProgressPercentageEvent) OutputStreamWriter(java.io.OutputStreamWriter) CryptoException(org.opendatakit.briefcase.model.CryptoException) File(java.io.File)

Example 3 with ParsingException

use of org.opendatakit.briefcase.model.ParsingException in project briefcase by opendatakit.

the class FileSystemUtils method decryptAndValidateSubmission.

public static DecryptOutcome decryptAndValidateSubmission(Document doc, PrivateKey rsaPrivateKey, File instanceDir, File unEncryptedDir) throws ParsingException, FileSystemException, CryptoException {
    Element rootElement = doc.getRootElement();
    String base64EncryptedSymmetricKey;
    String instanceIdMetadata = null;
    List<String> mediaNames = new ArrayList<>();
    String encryptedSubmissionFile;
    String base64EncryptedElementSignature;
    {
        Element base64Key = null;
        Element base64Signature = null;
        Element encryptedXml = null;
        for (int i = 0; i < rootElement.getChildCount(); ++i) {
            if (rootElement.getType(i) == Node.ELEMENT) {
                Element child = rootElement.getElement(i);
                String name = child.getName();
                if (name.equals("base64EncryptedKey")) {
                    base64Key = child;
                } else if (name.equals("base64EncryptedElementSignature")) {
                    base64Signature = child;
                } else if (name.equals("encryptedXmlFile")) {
                    encryptedXml = child;
                } else if (name.equals("media")) {
                    Element media = child;
                    for (int j = 0; j < media.getChildCount(); ++j) {
                        if (media.getType(j) == Node.ELEMENT) {
                            Element mediaChild = media.getElement(j);
                            String mediaFileElementName = mediaChild.getName();
                            if (mediaFileElementName.equals("file")) {
                                String mediaName = XFormParser.getXMLText(mediaChild, true);
                                if (mediaName == null || mediaName.length() == 0) {
                                    mediaNames.add(null);
                                } else {
                                    mediaNames.add(mediaName);
                                }
                            }
                        }
                    }
                }
            }
        }
        // verify base64Key
        if (base64Key == null) {
            throw new ParsingException("Missing base64EncryptedKey element in encrypted form.");
        }
        base64EncryptedSymmetricKey = XFormParser.getXMLText(base64Key, true);
        // get instanceID out of OpenRosa meta block
        instanceIdMetadata = XmlManipulationUtils.getOpenRosaInstanceId(rootElement);
        if (instanceIdMetadata == null) {
            throw new ParsingException("Missing instanceID within meta block of encrypted form.");
        }
        // get submission filename
        if (encryptedXml == null) {
            throw new ParsingException("Missing encryptedXmlFile element in encrypted form.");
        }
        encryptedSubmissionFile = XFormParser.getXMLText(encryptedXml, true);
        if (base64Signature == null) {
            throw new ParsingException("Missing base64EncryptedElementSignature element in encrypted form.");
        }
        base64EncryptedElementSignature = XFormParser.getXMLText(base64Signature, true);
    }
    if (instanceIdMetadata == null || base64EncryptedSymmetricKey == null || base64EncryptedElementSignature == null || encryptedSubmissionFile == null) {
        throw new ParsingException("Missing one or more required elements of encrypted form.");
    }
    FormInstanceMetadata fim;
    try {
        fim = XmlManipulationUtils.getFormInstanceMetadata(rootElement);
    } catch (ParsingException e) {
        String msg = "Unable to extract form instance metadata from submission manifest";
        log.error(msg, e);
        throw new ParsingException(msg + ". Cause: " + e.toString());
    }
    if (!instanceIdMetadata.equals(fim.instanceId)) {
        throw new ParsingException("InstanceID within metadata does not match that on top level element.");
    }
    boolean isValidated = FileSystemUtils.decryptSubmissionFiles(base64EncryptedSymmetricKey, fim, mediaNames, encryptedSubmissionFile, base64EncryptedElementSignature, rsaPrivateKey, instanceDir, unEncryptedDir);
    // and change doc to be the decrypted submission document
    File decryptedSubmission = new File(unEncryptedDir, "submission.xml");
    doc = XmlManipulationUtils.parseXml(decryptedSubmission);
    if (doc == null) {
        return null;
    }
    // verify that the metadata matches between the manifest and the submission
    rootElement = doc.getRootElement();
    FormInstanceMetadata sim = XmlManipulationUtils.getFormInstanceMetadata(rootElement);
    if (!fim.xparam.equals(sim.xparam)) {
        throw new ParsingException("FormId or version in decrypted submission does not match that in manifest!");
    }
    if (!fim.instanceId.equals(sim.instanceId)) {
        throw new ParsingException("InstanceId in decrypted submission does not match that in manifest!");
    }
    return new DecryptOutcome(doc, isValidated);
}
Also used : FormInstanceMetadata(org.opendatakit.briefcase.util.XmlManipulationUtils.FormInstanceMetadata) Element(org.kxml2.kdom.Element) ParsingException(org.opendatakit.briefcase.model.ParsingException) ArrayList(java.util.ArrayList) File(java.io.File)

Example 4 with ParsingException

use of org.opendatakit.briefcase.model.ParsingException in project briefcase by opendatakit.

the class XmlManipulationUtils method parseSubmissionDownloadListResponse.

public static final SubmissionChunk parseSubmissionDownloadListResponse(Document doc) throws ParsingException {
    List<String> uriList = new ArrayList<>();
    String websafeCursorString = "";
    // Attempt parsing
    Element idChunkElement = doc.getRootElement();
    if (!idChunkElement.getName().equals("idChunk")) {
        String msg = "Parsing submissionList reply -- root element is not <idChunk> :" + idChunkElement.getName();
        log.error(msg);
        throw new ParsingException(msg);
    }
    String namespace = idChunkElement.getNamespace();
    if (!namespace.equalsIgnoreCase(NAMESPACE_OPENDATAKIT_ORG_SUBMISSIONS)) {
        String msg = "Parsing submissionList reply -- root element namespace is incorrect:" + namespace;
        log.error(msg);
        throw new ParsingException(msg);
    }
    int nElements = idChunkElement.getChildCount();
    for (int i = 0; i < nElements; ++i) {
        if (idChunkElement.getType(i) != Element.ELEMENT) {
            // e.g., whitespace (text)
            continue;
        }
        Element subElement = (Element) idChunkElement.getElement(i);
        namespace = subElement.getNamespace();
        if (!namespace.equalsIgnoreCase(NAMESPACE_OPENDATAKIT_ORG_SUBMISSIONS)) {
            // someone else's extension?
            continue;
        }
        String name = subElement.getName();
        if (name.equalsIgnoreCase("idList")) {
            // parse the idList
            int nIdElements = subElement.getChildCount();
            for (int j = 0; j < nIdElements; ++j) {
                if (subElement.getType(j) != Element.ELEMENT) {
                    // e.g., whitespace (text)
                    continue;
                }
                Element idElement = (Element) subElement.getElement(j);
                namespace = idElement.getNamespace();
                if (!namespace.equalsIgnoreCase(NAMESPACE_OPENDATAKIT_ORG_SUBMISSIONS)) {
                    // someone else's extension?
                    continue;
                }
                name = idElement.getName();
                if (name.equalsIgnoreCase("id")) {
                    // gather the uri
                    String uri = XFormParser.getXMLText(idElement, true);
                    if (uri != null) {
                        uriList.add(uri);
                    }
                } else {
                    log.warn("Unrecognized tag inside idList: " + name);
                }
            }
        } else if (name.equalsIgnoreCase("resumptionCursor")) {
            // gather the resumptionCursor
            websafeCursorString = XFormParser.getXMLText(subElement, true);
            if (websafeCursorString == null) {
                websafeCursorString = "";
            }
        } else {
            log.warn("Unrecognized tag inside idChunk: " + name);
        }
    }
    return new SubmissionChunk(uriList, websafeCursorString);
}
Also used : Element(org.kxml2.kdom.Element) ParsingException(org.opendatakit.briefcase.model.ParsingException) ArrayList(java.util.ArrayList) SubmissionChunk(org.opendatakit.briefcase.util.ServerFetcher.SubmissionChunk)

Example 5 with ParsingException

use of org.opendatakit.briefcase.model.ParsingException in project briefcase by opendatakit.

the class ServerFetcher method downloadManifestAndMediaFiles.

private String downloadManifestAndMediaFiles(File mediaDir, FormStatus fs) {
    RemoteFormDefinition fd = getRemoteFormDefinition(fs);
    if (fd.getManifestUrl() == null)
        return null;
    fs.setStatusString("Fetching form manifest", true);
    EventBus.publish(new FormStatusEvent(fs));
    List<MediaFile> files = new ArrayList<>();
    AggregateUtils.DocumentFetchResult result;
    try {
        DocumentDescription formManifestDescription = new DocumentDescription("Fetch of manifest failed. Detailed reason: ", "Fetch of manifest failed ", "form manifest", terminationFuture);
        result = AggregateUtils.getXmlDocument(fd.getManifestUrl(), serverInfo, false, formManifestDescription, null);
    } catch (XmlDocumentFetchException e) {
        return e.getMessage();
    }
    try {
        files = XmlManipulationUtils.parseFormManifestResponse(result.isOpenRosaResponse, result.doc);
    } catch (ParsingException e) {
        return e.getMessage();
    }
    // OK we now have the full set of files to download...
    log.info("Downloading " + files.size() + " media files.");
    int mCount = 0;
    if (files.size() > 0) {
        for (MediaFile m : files) {
            ++mCount;
            fs.setStatusString(String.format(" (getting %1$d of %2$d media files)", mCount, files.size()), true);
            EventBus.publish(new FormStatusEvent(fs));
            try {
                downloadMediaFileIfChanged(mediaDir, m, fs);
            } catch (Exception e) {
                return e.getLocalizedMessage();
            }
        }
    }
    return null;
}
Also used : XmlDocumentFetchException(org.opendatakit.briefcase.model.XmlDocumentFetchException) DocumentDescription(org.opendatakit.briefcase.model.DocumentDescription) RemoteFormDefinition(org.opendatakit.briefcase.model.RemoteFormDefinition) FormStatusEvent(org.opendatakit.briefcase.model.FormStatusEvent) ParsingException(org.opendatakit.briefcase.model.ParsingException) ArrayList(java.util.ArrayList) URISyntaxException(java.net.URISyntaxException) FileSystemException(org.opendatakit.briefcase.model.FileSystemException) SQLException(java.sql.SQLException) SocketTimeoutException(java.net.SocketTimeoutException) TransmissionException(org.opendatakit.briefcase.model.TransmissionException) XmlDocumentFetchException(org.opendatakit.briefcase.model.XmlDocumentFetchException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) ParsingException(org.opendatakit.briefcase.model.ParsingException)

Aggregations

ParsingException (org.opendatakit.briefcase.model.ParsingException)15 File (java.io.File)9 IOException (java.io.IOException)9 FileSystemException (org.opendatakit.briefcase.model.FileSystemException)8 ArrayList (java.util.ArrayList)7 Element (org.kxml2.kdom.Element)5 FormStatusEvent (org.opendatakit.briefcase.model.FormStatusEvent)4 OutputStreamWriter (java.io.OutputStreamWriter)3 Document (org.kxml2.kdom.Document)3 CannotFixXMLException (org.opendatakit.briefcase.model.CannotFixXMLException)3 DocumentDescription (org.opendatakit.briefcase.model.DocumentDescription)3 MediaFile (org.opendatakit.briefcase.util.ServerFetcher.MediaFile)3 FileNotFoundException (java.io.FileNotFoundException)2 MalformedURLException (java.net.MalformedURLException)2 SQLException (java.sql.SQLException)2 LocalDate (java.time.LocalDate)2 Date (java.util.Date)2 HashMap (java.util.HashMap)2 CryptoException (org.opendatakit.briefcase.model.CryptoException)2 MetadataUpdateException (org.opendatakit.briefcase.model.MetadataUpdateException)2