Search in sources :

Example 6 with Document

use of org.kxml2.kdom.Document in project collect by opendatakit.

the class WebUtils method getXmlDocument.

/**
 * Common method for returning a parsed xml document given a url and the
 * http context and client objects involved in the web connection.
 */
public static DocumentFetchResult getXmlDocument(String urlString, HttpContext localContext, HttpClient httpclient) {
    URI u;
    try {
        URL url = new URL(urlString);
        u = url.toURI();
    } catch (URISyntaxException | MalformedURLException e) {
        Timber.i(e, "Error converting URL %s to uri", urlString);
        return new DocumentFetchResult(e.getLocalizedMessage() + // + app.getString(R.string.while_accessing) + urlString);
        ("while accessing") + urlString, 0);
    }
    if (u.getHost() == null) {
        return new DocumentFetchResult("Invalid server URL (no hostname): " + urlString, 0);
    }
    // if https then enable preemptive basic auth...
    if (u.getScheme().equals("https")) {
        enablePreemptiveBasicAuth(localContext, u.getHost());
    }
    // set up request...
    HttpGet req = WebUtils.createOpenRosaHttpGet(u);
    req.addHeader(WebUtils.ACCEPT_ENCODING_HEADER, WebUtils.GZIP_CONTENT_ENCODING);
    HttpResponse response;
    try {
        response = httpclient.execute(req, localContext);
        int statusCode = response.getStatusLine().getStatusCode();
        HttpEntity entity = response.getEntity();
        if (statusCode != HttpStatus.SC_OK) {
            WebUtils.discardEntityBytes(response);
            if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
                // clear the cookies -- should not be necessary?
                Collect.getInstance().getCookieStore().clear();
            }
            String webError = response.getStatusLine().getReasonPhrase() + " (" + statusCode + ")";
            return new DocumentFetchResult(u.toString() + " responded with: " + webError, statusCode);
        }
        if (entity == null) {
            String error = "No entity body returned from: " + u.toString();
            Timber.e(error);
            return new DocumentFetchResult(error, 0);
        }
        if (!entity.getContentType().getValue().toLowerCase(Locale.ENGLISH).contains(WebUtils.HTTP_CONTENT_TYPE_TEXT_XML)) {
            WebUtils.discardEntityBytes(response);
            String error = "ContentType: " + entity.getContentType().getValue() + " returned from: " + u.toString() + " is not text/xml.  This is often caused a network proxy.  Do you need " + "to login to your network?";
            Timber.e(error);
            return new DocumentFetchResult(error, 0);
        }
        // parse response
        Document doc = null;
        try {
            InputStream is = null;
            InputStreamReader isr = null;
            try {
                is = entity.getContent();
                Header contentEncoding = entity.getContentEncoding();
                if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase(WebUtils.GZIP_CONTENT_ENCODING)) {
                    is = new GZIPInputStream(is);
                }
                isr = new InputStreamReader(is, "UTF-8");
                doc = new Document();
                KXmlParser parser = new KXmlParser();
                parser.setInput(isr);
                parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
                doc.parse(parser);
                isr.close();
                isr = null;
            } finally {
                if (isr != null) {
                    try {
                        // ensure stream is consumed...
                        final long count = 1024L;
                        while (isr.skip(count) == count) {
                        // skipping to the end of the http entity
                        }
                    } catch (Exception e) {
                        // no-op
                        Timber.e(e);
                    }
                    try {
                        isr.close();
                    } catch (IOException e) {
                        // no-op
                        Timber.e(e, "Error closing input stream reader");
                    }
                }
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        Timber.e(e, "Error closing inputstream");
                    // no-op
                    }
                }
            }
        } catch (Exception e) {
            String error = "Parsing failed with " + e.getMessage() + "while accessing " + u.toString();
            Timber.e(error);
            return new DocumentFetchResult(error, 0);
        }
        boolean isOR = false;
        Header[] fields = response.getHeaders(WebUtils.OPEN_ROSA_VERSION_HEADER);
        if (fields != null && fields.length >= 1) {
            isOR = true;
            boolean versionMatch = false;
            boolean first = true;
            StringBuilder b = new StringBuilder();
            for (Header h : fields) {
                if (WebUtils.OPEN_ROSA_VERSION.equals(h.getValue())) {
                    versionMatch = true;
                    break;
                }
                if (!first) {
                    b.append("; ");
                }
                first = false;
                b.append(h.getValue());
            }
            if (!versionMatch) {
                Timber.w("%s unrecognized version(s): %s", WebUtils.OPEN_ROSA_VERSION_HEADER, b.toString());
            }
        }
        return new DocumentFetchResult(doc, isOR);
    } catch (Exception e) {
        String cause;
        Throwable c = e;
        while (c.getCause() != null) {
            c = c.getCause();
        }
        cause = c.toString();
        String error = "Error: " + cause + " while accessing " + u.toString();
        Timber.w(error);
        return new DocumentFetchResult(error, 0);
    }
}
Also used : MalformedURLException(java.net.MalformedURLException) HttpEntity(org.opendatakit.httpclientandroidlib.HttpEntity) InputStreamReader(java.io.InputStreamReader) GZIPInputStream(java.util.zip.GZIPInputStream) InputStream(java.io.InputStream) HttpGet(org.opendatakit.httpclientandroidlib.client.methods.HttpGet) HttpResponse(org.opendatakit.httpclientandroidlib.HttpResponse) URISyntaxException(java.net.URISyntaxException) IOException(java.io.IOException) Document(org.kxml2.kdom.Document) URI(java.net.URI) URL(java.net.URL) URISyntaxException(java.net.URISyntaxException) MalformedURLException(java.net.MalformedURLException) IOException(java.io.IOException) GZIPInputStream(java.util.zip.GZIPInputStream) KXmlParser(org.kxml2.io.KXmlParser) Header(org.opendatakit.httpclientandroidlib.Header)

Example 7 with Document

use of org.kxml2.kdom.Document in project javarosa by opendatakit.

the class XFormSerializer method getUtfBytes.

public static byte[] getUtfBytes(Document doc) {
    KXmlSerializer serializer = new KXmlSerializer();
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    try {
        Writer osw = new OutputStreamWriter(bos, "UTF-8");
        serializer.setOutput(osw);
        doc.write(serializer);
        serializer.flush();
        return bos.toByteArray();
    } catch (Exception e) {
        Std.printStack(e);
        return null;
    }
}
Also used : OutputStreamWriter(java.io.OutputStreamWriter) ByteArrayOutputStream(java.io.ByteArrayOutputStream) KXmlSerializer(org.kxml2.io.KXmlSerializer) Writer(java.io.Writer) OutputStreamWriter(java.io.OutputStreamWriter) UnsupportedEncodingException(java.io.UnsupportedEncodingException)

Example 8 with Document

use of org.kxml2.kdom.Document in project javarosa by opendatakit.

the class XFormSerializingVisitor method visit.

/*
     * (non-Javadoc)
     * @see org.javarosa.core.model.utils.ITreeVisitor#visit(org.javarosa.core.model.DataModelTree)
     */
public void visit(FormInstance tree) {
    theXmlDoc = new Document();
    // TreeElement root = tree.getRoot();
    TreeElement root = tree.resolveReference(rootRef);
    // catch that case and just start at the root.
    if (root == null) {
        root = tree.getRoot();
    }
    if (root != null) {
        theXmlDoc.addChild(Node.ELEMENT, serializeNode(root));
    }
    Element top = theXmlDoc.getElement(0);
    String[] prefixes = tree.getNamespacePrefixes();
    for (int i = 0; i < prefixes.length; ++i) {
        top.setPrefix(prefixes[i], tree.getNamespaceURI(prefixes[i]));
    }
    if (tree.schema != null) {
        top.setNamespace(tree.schema);
        top.setPrefix("", tree.schema);
    }
}
Also used : TreeElement(org.javarosa.core.model.instance.TreeElement) Element(org.kxml2.kdom.Element) Document(org.kxml2.kdom.Document) TreeElement(org.javarosa.core.model.instance.TreeElement)

Example 9 with Document

use of org.kxml2.kdom.Document 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 10 with Document

use of org.kxml2.kdom.Document 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)

Aggregations

IOException (java.io.IOException)18 KXmlParser (org.kxml2.io.KXmlParser)12 Document (org.kxml2.kdom.Document)11 Element (org.kxml2.kdom.Element)11 XmlPullParserException (org.xmlpull.v1.XmlPullParserException)11 ParsingException (org.opendatakit.briefcase.model.ParsingException)8 File (java.io.File)6 URL (java.net.URL)6 ArrayList (java.util.ArrayList)6 KXmlSerializer (org.kxml2.io.KXmlSerializer)6 FileNotFoundException (java.io.FileNotFoundException)5 InputStreamReader (java.io.InputStreamReader)5 UnsupportedEncodingException (java.io.UnsupportedEncodingException)5 InputStream (java.io.InputStream)4 MalformedURLException (java.net.MalformedURLException)4 FileSystemException (org.opendatakit.briefcase.model.FileSystemException)4 MetadataUpdateException (org.opendatakit.briefcase.model.MetadataUpdateException)4 MediaFile (org.opendatakit.briefcase.util.ServerFetcher.MediaFile)4 FileInputStream (java.io.FileInputStream)3 OutputStreamWriter (java.io.OutputStreamWriter)3