diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 79fffa96b..ca3d20951 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,6 +1,6 @@ - Validator: * enforce minValue and maxValue for decimal and Quantity types +* add checks for whitespace in base64 content (warning in = 0; + } + } \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java index f489c39eb..5eaf4c981 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java @@ -688,7 +688,8 @@ public class I18nConstants { public static final String TYPE_SPECIFIC_CHECKS_DT_QTY_MAX_MIN_NO_CONVERT = "TYPE_SPECIFIC_CHECKS_DT_QTY_MAX_MIN_NO_CONVERT"; public static final String TYPE_SPECIFIC_CHECKS_DT_QTY_MAX_VALUE_WRONG = "TYPE_SPECIFIC_CHECKS_DT_QTY_MAX_VALUE_WRONG"; public static final String TYPE_SPECIFIC_CHECKS_DT_QTY_MAX_VALUE_WRONG_UCUM = "TYPE_SPECIFIC_CHECKS_DT_QTY_MAX_VALUE_WRONG_UCUM"; - + public static final String TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_ERROR = "TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_ERROR"; + public static final String TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_WARNING = "TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_WARNING"; } diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index 83d301ed5..e9e2d0e97 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -698,4 +698,6 @@ TYPE_SPECIFIC_CHECKS_DT_QTY_MAX_NO_UCUM_SVC = There is no UCUM service, and the TYPE_SPECIFIC_CHECKS_DT_QTY_MAX_MIN_NO_CONVERT = Unable to convert value {0} from unit {1} to maxValue unit {2} based on UCUM definitions; maximum value is not valid TYPE_SPECIFIC_CHECKS_DT_QTY_MAX_VALUE_WRONG = The value in the instance ({2}) is greater than the specified maximum value ({3}) TYPE_SPECIFIC_CHECKS_DT_QTY_MAX_VALUE_WRONG_UCUM = The value in the instance ({0} {1}) is greater than the specified maxValue ({2} {3}) after UCUM conversion +TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_ERROR = Base64 values are not allowed to contain any whitespace (per RFC 4648). Note that non-validating readers are encouraged to accept whitespace anyway +TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_WARNING = Base64 values SHOULD not contain any whitespace (per RFC 4648). Note that non-validating readers are encouraged to accept whitespace anyway diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java index 439a471bb..485cee2c6 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java @@ -2216,6 +2216,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (!ok) { String value = encoded.length() < 100 ? encoded : "(snip)"; rule(errors, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_BASE64_VALID, value); + } else { + boolean wsok = base64HasWhitespace(encoded); + if (VersionUtilities.isR5VerOrLater(this.context.getVersion())) { + rule(errors, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_ERROR); + } else { + warning(errors, IssueType.INVALID, e.line(), e.col(), path, false, I18nConstants.TYPE_SPECIFIC_CHECKS_DT_BASE64_NO_WS_WARNING); + } } if (ok && context.hasExtension("http://hl7.org/fhir/StructureDefinition/maxSize")) { int size = countBase64DecodedBytes(encoded); @@ -2420,6 +2427,20 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return ok; } + private boolean base64HasWhitespace(String theEncoded) { + if (theEncoded == null) { + return false; + } + for (int i = 0; i < theEncoded.length(); i++) { + char nextChar = theEncoded.charAt(i); + if (Character.isWhitespace(nextChar)) { + return true; + } + } + return false; + + } + private int countBase64DecodedBytes(String theEncoded) { Base64InputStream inputStream = new Base64InputStream(new ByteArrayInputStream(theEncoded.getBytes(StandardCharsets.UTF_8)));