Skip to content

Commit

Permalink
Merge pull request #516 from entur/improve/id-validation
Browse files Browse the repository at this point in the history
Improve/id validation
  • Loading branch information
testower authored Aug 5, 2024
2 parents 471be01 + d7839ba commit 9bf35fc
Show file tree
Hide file tree
Showing 12 changed files with 903 additions and 10 deletions.
6 changes: 0 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
<gbfs-loader-java.version>4.0.8</gbfs-loader-java.version>
<gbfs-validator-java.version>2.0.6</gbfs-validator-java.version>
<gbfs-mapper-java.version>2.0.6</gbfs-mapper-java.version>
<netex-utils.version>1.46</netex-utils.version>
<prettier-java.version>2.1.0</prettier-java.version>
<prettier-maven-plugin.version>0.22</prettier-maven-plugin.version>
<plugin.prettier.goal>write</plugin.prettier.goal>
Expand Down Expand Up @@ -150,11 +149,6 @@
<artifactId>kryo</artifactId>
<version>${kryo.version}</version>
</dependency>
<dependency>
<groupId>no.entur.abt</groupId>
<artifactId>netex-utils</artifactId>
<version>${netex-utils.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import no.entur.abt.netex.id.NetexIdBuilder;
import no.entur.abt.netex.id.predicate.NetexIdPredicateBuilder;
import org.entur.lamassu.model.id.IdBuilder;
import org.entur.lamassu.model.id.predicate.IdPredicateBuilder;
import org.entur.lamassu.model.provider.FeedProvider;

public class IdMappers {
Expand All @@ -43,15 +43,15 @@ public static String mapId(String codespace, String type, String value) {
return value;
}

var predicate = NetexIdPredicateBuilder
var predicate = IdPredicateBuilder
.newInstance()
.withCodespace(codespace)
.withType(type)
.build();
if (predicate.test(value)) {
return value;
} else {
return NetexIdBuilder
return IdBuilder
.newInstance()
.withCodespace(codespace)
.withType(type)
Expand Down
121 changes: 121 additions & 0 deletions src/main/java/org/entur/lamassu/model/id/DefaultIdValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
*
*
* * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by
* * the European Commission - subsequent versions of the EUPL (the "Licence");
* * You may not use this work except in compliance with the Licence.
* * You may obtain a copy of the Licence at:
* *
* * https://joinup.ec.europa.eu/software/page/eupl
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the Licence is distributed on an "AS IS" basis,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the Licence for the specific language governing permissions and
* * limitations under the Licence.
*
*/

package org.entur.lamassu.model.id;

import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DefaultIdValidator implements IdValidator {

public static final char ID_SEPARATOR_CHAR = ':';
public static final int ID_CODESPACE_LENGTH = 3;
public static final int ID_MINIMUM_LENGTH = 6;

protected static final DefaultIdValidator instance = new DefaultIdValidator();
private static final Logger log = LoggerFactory.getLogger(DefaultIdValidator.class);

public static DefaultIdValidator getInstance() {
return instance;
}

public boolean validate(CharSequence string, int offset, int length) {
// minimum size is XXX:X:X
if (length < ID_MINIMUM_LENGTH) {
return false;
}
if (string.charAt(offset + ID_CODESPACE_LENGTH) != ':') {
return false;
}
int nextSeparatorIndex = getNextSeparatorIndex(
string,
ID_CODESPACE_LENGTH + 1,
length
);
if (nextSeparatorIndex == -1) {
return false;
}
return (
validateCodespace(string, 0, ID_CODESPACE_LENGTH) &&
validateType(string, ID_CODESPACE_LENGTH + 1, nextSeparatorIndex) &&
validateValue(string, nextSeparatorIndex + 1, string.length())
);
}

protected static int getNextSeparatorIndex(
CharSequence string,
int startIndex,
int endIndex
) {
for (int i = startIndex; i < endIndex; i++) {
if (string.charAt(i) == ID_SEPARATOR_CHAR) {
return i;
}
}
return -1;
}

public boolean validateCodespace(CharSequence codespace, int startIndex, int endIndex) {
// length 3
// A-Z
if (endIndex - startIndex == ID_CODESPACE_LENGTH) {
for (int i = startIndex; i < endIndex; i++) {
char c = codespace.charAt(i);
if (c < 'A' || c > 'Z') {
return false;
}
}
return true;
}
return false;
}

public boolean validateType(CharSequence type, int startIndex, int endIndex) {
// not empty string
// A-Z
// a-z
if (endIndex > startIndex) {
for (int i = startIndex; i < endIndex; i++) {
char c = type.charAt(i);
if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))) {
return false;
}
}
return true;
}
return false;
}

public boolean validateValue(CharSequence value, int startIndex, int endIndex) {
if (endIndex > startIndex) {
for (int i = startIndex; i < endIndex; i++) {
char c = value.charAt(i);
if (!isValueCharacter(c)) {
return false;
}
}
return true;
}
return false;
}

protected static boolean isValueCharacter(char c) {
return c >= 0x21 && c <= 0x7E; // Not in the ASCII printable range
}
}
79 changes: 79 additions & 0 deletions src/main/java/org/entur/lamassu/model/id/IdBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
*
*
* * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by
* * the European Commission - subsequent versions of the EUPL (the "Licence");
* * You may not use this work except in compliance with the Licence.
* * You may obtain a copy of the Licence at:
* *
* * https://joinup.ec.europa.eu/software/page/eupl
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the Licence is distributed on an "AS IS" basis,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the Licence for the specific language governing permissions and
* * limitations under the Licence.
*
*/

package org.entur.lamassu.model.id;

public class IdBuilder {

public static IdBuilder newInstance() {
return new IdBuilder();
}

protected static final String ID_SEPARATOR_CHAR = ":";

private static final IdValidator defaultValidator = DefaultIdValidator.getInstance();

private final IdValidator validator;

protected String codespace;
protected String type;
protected String value;

public IdBuilder() {
this(defaultValidator);
}

public IdBuilder(IdValidator validator) {
this.validator = validator;
}

public IdBuilder withCodespace(String codespace) {
this.codespace = codespace;
return this;
}

public IdBuilder withType(String type) {
this.type = type;
return this;
}

public IdBuilder withValue(String value) {
this.value = value;

return this;
}

public String build() {
if (codespace == null || !validator.validateCodespace(codespace)) {
throw new IllegalStateException(
"Expected codespace (size 3 with characters A-Z), found " + codespace
);
}
if (type == null || !validator.validateType(type)) {
throw new IllegalStateException(
"Expected type (nonempty with characters A-Z), found " + type
);
}
if (value == null || !validator.validateValue(value)) {
throw new IllegalStateException(
"Expected value (ASCII printable character), found " + value
);
}
return String.join(ID_SEPARATOR_CHAR, codespace, type, value);
}
}
45 changes: 45 additions & 0 deletions src/main/java/org/entur/lamassu/model/id/IdValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
*
*
* * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by
* * the European Commission - subsequent versions of the EUPL (the "Licence");
* * You may not use this work except in compliance with the Licence.
* * You may obtain a copy of the Licence at:
* *
* * https://joinup.ec.europa.eu/software/page/eupl
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the Licence is distributed on an "AS IS" basis,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the Licence for the specific language governing permissions and
* * limitations under the Licence.
*
*/

package org.entur.lamassu.model.id;

public interface IdValidator {
default boolean validate(CharSequence id) {
return validate(id, 0, id.length());
}

boolean validate(CharSequence id, int offset, int length);

default boolean validateCodespace(CharSequence codespace) {
return validateCodespace(codespace, 0, codespace.length());
}

boolean validateCodespace(CharSequence codespace, int offset, int length);

default boolean validateType(CharSequence type) {
return validateType(type, 0, type.length());
}

boolean validateType(CharSequence type, int offset, int length);

default boolean validateValue(CharSequence value) {
return validateValue(value, 0, value.length());
}

boolean validateValue(CharSequence value, int offset, int length);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
*
*
* * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by
* * the European Commission - subsequent versions of the EUPL (the "Licence");
* * You may not use this work except in compliance with the Licence.
* * You may obtain a copy of the Licence at:
* *
* * https://joinup.ec.europa.eu/software/page/eupl
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the Licence is distributed on an "AS IS" basis,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the Licence for the specific language governing permissions and
* * limitations under the Licence.
*
*/

package org.entur.lamassu.model.id.predicate;

import org.entur.lamassu.model.id.DefaultIdValidator;

public class IdCodespacePredicate implements IdPredicate {

private final char[] prefix;

public IdCodespacePredicate(CharSequence codespace) {
prefix =
new char[] {
codespace.charAt(0),
codespace.charAt(1),
codespace.charAt(2),
DefaultIdValidator.ID_SEPARATOR_CHAR,
};
}

public boolean test(CharSequence t) {
return (
t.length() > 4 &&
t.charAt(0) == prefix[0] &&
t.charAt(1) == prefix[1] &&
t.charAt(2) == prefix[2] &&
t.charAt(3) == prefix[3]
);
}
}
Loading

0 comments on commit 9bf35fc

Please sign in to comment.