/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> * BPS Bildungsportal Sachsen GmbH, http://www.bps-system.de * <p> */ package de.bps.onyx.util; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import org.apache.commons.codec.digest.DigestUtils; /** * Validates the checksum in Onyx test summary HTML files. * */ //<OLATCE-1399> public class SummaryCheckSumValidator { // private static final Logger log = LoggerFactory.getLogger(SummaryCheckSumValidator.class); private static final String STRONG = "<strong>"; /** * used only for stand-alone checks see * /src/main/resources/summaryCheckSumValidator/READ.ME */ public static void main(final String[] args) { if (args.length != 1) { System.err.println("Missing file-parameter!\nPlease call this program like \"java -jar SummaryCheckSumValidator summary.html\""); System.exit(1); } final String filename = args[0]; final SummaryChecksumValidatorResult result = validate(filename); final boolean fileIsValid = result.validated; if (fileIsValid) { System.out.println("File could be validated!"); System.out.println("Result : " + result.result); } else { System.err.println("File could not be validated!"); System.err.println("Reason: " + result.result); System.err.println("Info : " + result.info); } } /** * Validates the Onyx test result summary pages checksum. * * @param file * The file containing the summary HTML * @return SummaryChecksumValidatorResult structure. The contained validated * field contains the validation result. * * @see SummaryChecksumValidatorResult */ public static SummaryChecksumValidatorResult validate(final File file) { FileInputStream fis = null; final ByteArrayOutputStream baos = new ByteArrayOutputStream((int) file.length()); try { fis = new FileInputStream(file); final byte[] buf = new byte[102400]; int read = 0; while ((read = fis.read(buf)) >= 0) { baos.write(buf, 0, read); } } catch (final IOException e) { // log.error("Error reading file to validate: " + file.getAbsolutePath(), e); final SummaryChecksumValidatorResult result = new SummaryChecksumValidatorResult(); result.result = "onyx.summary.validation.result.error.reading.file"; result.info = file.getAbsolutePath() + " - " + e.getMessage(); return result; } finally { try { if (fis != null) { fis.close(); fis = null; } } catch (final Exception e) { // ignore } } try { baos.flush(); } catch (final IOException e) { // ignore } final String html = baos.toString(); try { baos.close(); } catch (final IOException e) { // ignore } return internalValidate(html); } /** * Validates the Onyx test result summary pages checksum. * * @param filename * The filename of the file containing the summary HTML * @return SummaryChecksumValidatorResult structure. The contained validated * field contains the validation result. * * @see SummaryChecksumValidatorResult */ public static SummaryChecksumValidatorResult validate(final String filename) { final File file = new File(filename); if (!file.exists()) { final SummaryChecksumValidatorResult result = new SummaryChecksumValidatorResult(); result.result = "onyx.summary.validation.result.file.not.found"; result.info = filename; return result; } return validate(file); } private static SummaryChecksumValidatorResult internalValidate(final String html) { final SummaryChecksumValidatorResult result = new SummaryChecksumValidatorResult(); // determine hashed HTML content final int start = html.indexOf(" <div class=\"test\">"); if (start > 0) { final int end = html.indexOf(" <div class=\"hash\">", start); if (end > 0) { final String toHash = html.substring(start, end); // if (log.isDebugEnabled()) { // log.debug("HTML to validate: " + toHash); // } // determine hash int startHash = html.indexOf(STRONG, end); if (startHash > 0) { startHash += STRONG.length(); final int endHash = html.indexOf("</strong>", startHash); if (endHash > 0) { final String hash = html.substring(startHash, endHash); // compare final String toCompare = DigestUtils.md5Hex(toHash); final boolean equal = hash.equals(toCompare); // if (log.isDebugEnabled()) { // log.debug("Hash to validate: " + hash); // log.debug("Hash to compare : " + toCompare); // log.debug("Equal: " + equal); // } if (equal) { result.result = "OK"; result.validated = true; return result; } } else { result.result = "onyx.summary.validation.result.hash.end.not.found"; } } else { result.result = "onyx.summary.validation.result.hash.start.not.found"; } } else { result.result = "onyx.summary.validation.result.content.end.not.found"; } } else { result.result = "onyx.summary.validation.result.content.start.not.found"; } return result; } /** * Summary HTML hash validator result class. Has two fields: validated * (true/false) if (not) validated and result as textual validation failure * reason. */ public static final class SummaryChecksumValidatorResult { /** Validation result */ public boolean validated = false; /** Result failure text (message key) */ public String result = ""; /** * More info if validation failed with an technical error (could not * read file, ...) */ public String info = ""; public SummaryChecksumValidatorResult() { validated = false; result = ""; info = ""; } } } /* history: $Log: SummaryCheckSumValidator.java,v $ Revision 1.2 2012-04-05 13:49:41 blaw OLATCE-1425 * added history * better indention * refactored referencess for ExamPoolManagers to the abstract class * added yesNoDialog for StartExam-function * added more gui-warnings and / or fallback-values if student- or exam-values are not available */