Skip to content

Commit 443e862

Browse files
authored
fix: core config type validation (#175)
* fix: core config type validation * fix: pr comments * fix: user config mapper * fix: config mapper
1 parent 28ca3e7 commit 443e862

File tree

5 files changed

+159
-5
lines changed

5 files changed

+159
-5
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## [Unreleased]
99

10+
## [5.0.6] - 2023-12-05
11+
12+
- Validates db config types in `canBeUsed` function
13+
1014
## [5.0.5] - 2023-11-23
1115

1216
- Fixes call to `getPrimaryUserInfoForUserIds_Transaction` in `listPrimaryUsersByThirdPartyInfo_Transaction`

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ plugins {
22
id 'java-library'
33
}
44

5-
version = "5.0.5"
5+
version = "5.0.6"
66

77
repositories {
88
mavenCentral()

src/main/java/io/supertokens/storage/postgresql/Start.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,7 @@ void handleKillSignalForWhenItHappens() {
719719
}
720720

721721
@Override
722-
public boolean canBeUsed(JsonObject configJson) {
722+
public boolean canBeUsed(JsonObject configJson) throws InvalidConfigException {
723723
return Config.canBeUsed(configJson);
724724
}
725725

src/main/java/io/supertokens/storage/postgresql/config/Config.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import io.supertokens.storage.postgresql.ResourceDistributor;
2727
import io.supertokens.storage.postgresql.Start;
2828
import io.supertokens.storage.postgresql.output.Logging;
29+
import io.supertokens.storage.postgresql.utils.ConfigMapper;
2930

3031
import java.io.IOException;
3132
import java.util.HashSet;
@@ -103,11 +104,12 @@ private PostgreSQLConfig loadPostgreSQLConfig(JsonObject configJson) throws IOEx
103104
return config;
104105
}
105106

106-
public static boolean canBeUsed(JsonObject configJson) {
107+
public static boolean canBeUsed(JsonObject configJson) throws InvalidConfigException {
107108
try {
108-
final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
109-
PostgreSQLConfig config = mapper.readValue(configJson.toString(), PostgreSQLConfig.class);
109+
PostgreSQLConfig config = ConfigMapper.mapConfig(configJson, PostgreSQLConfig.class);
110110
return config.getConnectionURI() != null || config.getUser() != null || config.getPassword() != null;
111+
} catch (InvalidConfigException e) {
112+
throw e;
111113
} catch (Exception e) {
112114
return false;
113115
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
* Copyright (c) 2023, VRAI Labs and/or its affiliates. All rights reserved.
3+
*
4+
* This software is licensed under the Apache License, Version 2.0 (the
5+
* "License") as published by the Apache Software Foundation.
6+
*
7+
* You may not use this file except in compliance with the License. You may
8+
* obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
17+
package io.supertokens.storage.postgresql.utils;
18+
19+
import com.fasterxml.jackson.annotation.JsonAlias;
20+
import com.fasterxml.jackson.annotation.JsonProperty;
21+
import com.google.gson.JsonElement;
22+
import com.google.gson.JsonNull;
23+
import com.google.gson.JsonObject;
24+
import io.supertokens.pluginInterface.exceptions.InvalidConfigException;
25+
26+
import java.lang.annotation.Annotation;
27+
import java.lang.reflect.Field;
28+
import java.util.Map;
29+
30+
public class ConfigMapper {
31+
public static <T> T mapConfig(JsonObject config, Class<T> clazz) throws InvalidConfigException {
32+
try {
33+
T result = clazz.newInstance();
34+
for (Map.Entry<String, JsonElement> entry : config.entrySet()) {
35+
Field field = findField(clazz, entry.getKey());
36+
if (field != null) {
37+
setValue(result, field, entry.getValue());
38+
}
39+
}
40+
return result;
41+
} catch (InstantiationException | IllegalAccessException e) {
42+
throw new RuntimeException(e);
43+
}
44+
}
45+
46+
private static <T> Field findField(Class<T> clazz, String key) {
47+
Field[] fields = clazz.getDeclaredFields();
48+
49+
for (Field field : fields) {
50+
if (field.getName().equals(key)) {
51+
return field;
52+
}
53+
54+
// Check for JsonProperty annotation
55+
JsonProperty jsonProperty = field.getAnnotation(JsonProperty.class);
56+
if (jsonProperty != null && jsonProperty.value().equals(key)) {
57+
return field;
58+
}
59+
60+
// Check for JsonAlias annotation
61+
JsonAlias jsonAlias = field.getAnnotation(JsonAlias.class);
62+
if (jsonAlias != null) {
63+
for (String alias : jsonAlias.value()) {
64+
if (alias.equals(key)) {
65+
return field;
66+
}
67+
}
68+
}
69+
}
70+
71+
return null; // Field not found
72+
}
73+
74+
private static <T> void setValue(T object, Field field, JsonElement value) throws InvalidConfigException {
75+
boolean foundAnnotation = false;
76+
for (Annotation a : field.getAnnotations()) {
77+
if (a.toString().contains("JsonProperty")) {
78+
foundAnnotation = true;
79+
break;
80+
}
81+
}
82+
83+
if (!foundAnnotation) {
84+
return;
85+
}
86+
87+
field.setAccessible(true);
88+
Object convertedValue = convertJsonElementToTargetType(value, field.getType(), field.getName());
89+
if (convertedValue != null) {
90+
try {
91+
field.set(object, convertedValue);
92+
} catch (IllegalAccessException e) {
93+
throw new IllegalStateException("should never happen");
94+
}
95+
}
96+
}
97+
98+
private static Object convertJsonElementToTargetType(JsonElement value, Class<?> targetType, String fieldName)
99+
throws InvalidConfigException {
100+
// If the value is JsonNull, return null for any type
101+
if (value instanceof JsonNull || value == null) {
102+
return null;
103+
}
104+
105+
try {
106+
if (targetType == String.class) {
107+
return value.getAsString();
108+
} else if (targetType == Integer.class || targetType == int.class) {
109+
if (value.getAsDouble() == (double) value.getAsInt()) {
110+
return value.getAsInt();
111+
}
112+
} else if (targetType == Long.class || targetType == long.class) {
113+
if (value.getAsDouble() == (double) value.getAsLong()) {
114+
return value.getAsLong();
115+
}
116+
} else if (targetType == Double.class || targetType == double.class) {
117+
return value.getAsDouble();
118+
} else if (targetType == Float.class || targetType == float.class) {
119+
return value.getAsFloat();
120+
} else if (targetType == Boolean.class || targetType == boolean.class) {
121+
// Handle boolean conversion from strings like "true", "false"
122+
return handleBooleanConversion(value, fieldName);
123+
}
124+
} catch (NumberFormatException e) {
125+
// do nothing, will fall into InvalidConfigException
126+
}
127+
128+
// Throw an exception for unsupported conversions
129+
throw new InvalidConfigException("'" + fieldName + "' must be of type " + targetType.getSimpleName());
130+
}
131+
132+
private static Object handleBooleanConversion(JsonElement value, String fieldName) throws InvalidConfigException {
133+
// Handle boolean conversion from strings like "true", "false"
134+
if (value.isJsonPrimitive() && value.getAsJsonPrimitive().isString()) {
135+
String stringValue = value.getAsString().toLowerCase();
136+
if (stringValue.equals("true")) {
137+
return true;
138+
} else if (stringValue.equals("false")) {
139+
return false;
140+
}
141+
} else if (value.isJsonPrimitive() && value.getAsJsonPrimitive().isBoolean()) {
142+
return value.getAsBoolean();
143+
}
144+
145+
// Throw an exception for unsupported conversions
146+
throw new InvalidConfigException("'" + fieldName + "' must be of type boolean");
147+
}
148+
}

0 commit comments

Comments
 (0)