|
|
@ -4,7 +4,8 @@ import java.sql.SQLException;
|
|
|
|
import java.sql.Statement;
|
|
|
|
import java.sql.Statement;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.function.Consumer;
|
|
|
|
|
|
|
|
import java.util.function.Supplier;
|
|
|
|
import java.util.stream.Stream;
|
|
|
|
import java.util.stream.Stream;
|
|
|
|
|
|
|
|
|
|
|
|
import org.apache.ibatis.executor.Executor;
|
|
|
|
import org.apache.ibatis.executor.Executor;
|
|
|
@ -12,48 +13,67 @@ import org.apache.ibatis.executor.resultset.ResultSetHandler;
|
|
|
|
import org.apache.ibatis.mapping.MappedStatement;
|
|
|
|
import org.apache.ibatis.mapping.MappedStatement;
|
|
|
|
import org.apache.ibatis.plugin.Intercepts;
|
|
|
|
import org.apache.ibatis.plugin.Intercepts;
|
|
|
|
import org.apache.ibatis.plugin.Signature;
|
|
|
|
import org.apache.ibatis.plugin.Signature;
|
|
|
|
|
|
|
|
import org.apache.ibatis.session.ResultHandler;
|
|
|
|
|
|
|
|
import org.apache.ibatis.session.RowBounds;
|
|
|
|
|
|
|
|
|
|
|
|
import cokr.xit.foundation.data.ARIA;
|
|
|
|
import cokr.xit.foundation.data.ARIA;
|
|
|
|
|
|
|
|
|
|
|
|
@Intercepts({
|
|
|
|
@Intercepts({
|
|
|
|
|
|
|
|
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
|
|
|
|
@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class}),
|
|
|
|
@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class}),
|
|
|
|
|
|
|
|
|
|
|
|
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
|
|
|
|
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
|
|
|
|
})
|
|
|
|
})
|
|
|
|
public class EncryptionSupport extends MybatisPlugin {
|
|
|
|
public class EncryptionSupport extends MybatisPlugin {
|
|
|
|
private boolean enabled;
|
|
|
|
private boolean enabled;
|
|
|
|
private ARIA aria = new ARIA();
|
|
|
|
private ARIA aria;
|
|
|
|
|
|
|
|
|
|
|
|
private List<String> decrypted = Collections.emptyList();
|
|
|
|
|
|
|
|
private List<Adaptor> adaptors = Collections.emptyList();
|
|
|
|
private List<Adaptor> adaptors = Collections.emptyList();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void setEnabled(boolean enabled) {
|
|
|
|
|
|
|
|
this.enabled = enabled;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void setEncryptor(ARIA encryptor) {
|
|
|
|
|
|
|
|
this.aria = encryptor;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void setAdaptors(Adaptor... adaptors) {
|
|
|
|
|
|
|
|
this.adaptors = List.of(adaptors);
|
|
|
|
|
|
|
|
this.adaptors.forEach(adaptor -> adaptor.setARIA(aria));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
protected void configure() {
|
|
|
|
protected void configure() {
|
|
|
|
String str = properties.getProperty("enabled", "");
|
|
|
|
String str = properties.getProperty("enabled", "");
|
|
|
|
enabled = !"false".equals(str);
|
|
|
|
setEnabled(!"false".equals(str));
|
|
|
|
|
|
|
|
|
|
|
|
str = properties.getProperty("enc.key");
|
|
|
|
if (aria == null) {
|
|
|
|
aria.setKey(str);
|
|
|
|
aria = new ARIA();
|
|
|
|
str = properties.getProperty("enc.algorithm");
|
|
|
|
aria.setKey(properties.getProperty("enc.key"));
|
|
|
|
if (!isEmpty(str))
|
|
|
|
str = properties.getProperty("enc.algorithm");
|
|
|
|
aria.setAlgorithm(str);
|
|
|
|
if (!isEmpty(str))
|
|
|
|
|
|
|
|
aria.setAlgorithm(str);
|
|
|
|
str = properties.getProperty("dec.fields", "");
|
|
|
|
}
|
|
|
|
if (!isEmpty(str))
|
|
|
|
|
|
|
|
decrypted = List.of(str.split(","));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
str = properties.getProperty("enc.adaptor", "");
|
|
|
|
str = properties.getProperty("enc.adaptor", "");
|
|
|
|
if (isEmpty(str)) return;
|
|
|
|
if (isEmpty(str)) return;
|
|
|
|
|
|
|
|
|
|
|
|
adaptors = Stream.of(str.split(",")).map(name -> {
|
|
|
|
List<Adaptor> adaptors = Stream.of(str.split(",")).map(name -> {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
Class<?> klass = Class.forName(name);
|
|
|
|
Class<?> klass = Class.forName(name);
|
|
|
|
Adaptor adaptor = (Adaptor)klass.getConstructor().newInstance();
|
|
|
|
return (Adaptor)klass.getConstructor().newInstance();
|
|
|
|
adaptor.setARIA(aria);
|
|
|
|
|
|
|
|
return adaptor;
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
} catch (Exception e) {
|
|
|
|
throw runtimeException(e);
|
|
|
|
throw runtimeException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}).toList();
|
|
|
|
}).toList();
|
|
|
|
|
|
|
|
setAdaptors(adaptors.toArray(new Adaptor[adaptors.size()]));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
protected Object query(Executor executor, MappedStatement mappedStatement, Object obj, RowBounds rowBounds, ResultHandler<?> resultHandler) throws SQLException {
|
|
|
|
|
|
|
|
encrypt(obj);
|
|
|
|
|
|
|
|
return executor.query(mappedStatement, obj, rowBounds, resultHandler);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
@ -71,18 +91,15 @@ public class EncryptionSupport extends MybatisPlugin {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void decrypt(Object obj) {
|
|
|
|
private void decrypt(Object obj) {
|
|
|
|
if (!enabled || decrypted.isEmpty()) return;
|
|
|
|
if (!enabled || adaptors.isEmpty()) return;
|
|
|
|
|
|
|
|
|
|
|
|
if (obj instanceof Map)
|
|
|
|
adaptors.forEach(adaptor -> {
|
|
|
|
decrypt((Map<String, Object>)obj);
|
|
|
|
if (!adaptor.supports(obj)) return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void decrypt(Map<String, Object> map) {
|
|
|
|
|
|
|
|
decrypted.forEach(k -> {
|
|
|
|
|
|
|
|
if (!map.containsKey(k)) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Object v = map.get(k);
|
|
|
|
adaptor
|
|
|
|
map.put(k, aria.decrypt((String)v));
|
|
|
|
.setTarget(obj)
|
|
|
|
|
|
|
|
.decrypt()
|
|
|
|
|
|
|
|
.clear();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -104,10 +121,12 @@ public class EncryptionSupport extends MybatisPlugin {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void encrypt(Adaptor adaptor, Object obj) {
|
|
|
|
private void encrypt(Adaptor adaptor, Object obj) {
|
|
|
|
if (!adaptor.setTarget(obj)) return;
|
|
|
|
if (!adaptor.supports(obj)) return;
|
|
|
|
|
|
|
|
|
|
|
|
adaptor.encrypt();
|
|
|
|
adaptor
|
|
|
|
adaptor.clear();
|
|
|
|
.setTarget(obj)
|
|
|
|
|
|
|
|
.encrypt()
|
|
|
|
|
|
|
|
.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public abstract static class Adaptor {
|
|
|
|
public abstract static class Adaptor {
|
|
|
@ -119,12 +138,32 @@ public class EncryptionSupport extends MybatisPlugin {
|
|
|
|
return this;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public boolean setTarget(Object obj) {
|
|
|
|
public Adaptor setTarget(Object obj) {
|
|
|
|
this.obj = obj;
|
|
|
|
this.obj = obj;
|
|
|
|
return true;
|
|
|
|
return this;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public abstract boolean supports(Object obj);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public abstract boolean isEncrypted(String str);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public abstract Adaptor encrypt();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public abstract Adaptor decrypt();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void encrypt(Supplier<String> getter, Consumer<String> setter) {
|
|
|
|
|
|
|
|
String plain = getter.get();
|
|
|
|
|
|
|
|
if (isEmpty(plain) || isEncrypted(plain)) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setter.accept(aria.encrypt(plain));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public abstract void encrypt();
|
|
|
|
protected void decrypt(Supplier<String> getter, Consumer<String> setter) {
|
|
|
|
|
|
|
|
String encrypted = getter.get();
|
|
|
|
|
|
|
|
if (isEmpty(encrypted) || !isEncrypted(encrypted)) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setter.accept(aria.decrypt(encrypted));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void clear() {
|
|
|
|
public void clear() {
|
|
|
|
obj = null;
|
|
|
|
obj = null;
|
|
|
|