mirror of
https://github.com/CodePhiliaX/Chat2DB.git
synced 2025-07-30 03:03:13 +08:00
@ -57,7 +57,7 @@ public class ConverterController {
|
||||
// 验证文件后缀
|
||||
String fileExtension = FileUtils.getFileExtension(Objects.requireNonNull(file.getOriginalFilename()));
|
||||
if (!fileExtension.equalsIgnoreCase(FileUtils.ConfigFile.DBP.name())) {
|
||||
return DataResult.error("1", "上传的文件必须是ncx文件!");
|
||||
return DataResult.error("1", "上传的文件必须是dbp文件!");
|
||||
}
|
||||
File temp = new File(ConfigUtils.CONFIG_BASE_PATH + File.separator + UUID.randomUUID() + ".tmp");
|
||||
file.transferTo(temp);
|
||||
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2023 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package ai.chat2db.server.web.api.controller.ncx.dbeaver;
|
||||
|
||||
/**
|
||||
* Value encryptor
|
||||
*/
|
||||
public interface DBSValueEncryptor {
|
||||
|
||||
byte[] encryptValue(byte[] value);
|
||||
|
||||
byte[] decryptValue(byte[] value);
|
||||
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2023 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ai.chat2db.server.web.api.controller.ncx.dbeaver;
|
||||
|
||||
import org.apache.poi.util.IOUtils;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.CipherInputStream;
|
||||
import javax.crypto.CipherOutputStream;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Default value encryptor.
|
||||
*
|
||||
* Uses Eclipse secure preferences to read/write secrets.
|
||||
*/
|
||||
public class DefaultValueEncryptor implements DBSValueEncryptor {
|
||||
|
||||
public static final String CIPHER_NAME = "AES/CBC/PKCS5Padding";
|
||||
public static final String KEY_ALGORITHM = "AES";
|
||||
|
||||
private static final byte[] LOCAL_KEY_CACHE = new byte[] { -70, -69, 74, -97, 119, 74, -72, 83, -55, 108, 45, 101, 61, -2, 84, 74 };
|
||||
|
||||
private final SecretKey secretKey;
|
||||
private final Cipher cipher;
|
||||
|
||||
public DefaultValueEncryptor(SecretKey secretKey) {
|
||||
this.secretKey = secretKey;
|
||||
try {
|
||||
this.cipher = Cipher.getInstance(CIPHER_NAME);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Internal error during encrypted init", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过 DBeaver 源码查看到默认的 SecretKey
|
||||
**/
|
||||
public static SecretKey getLocalSecretKey() {
|
||||
return new SecretKeySpec(LOCAL_KEY_CACHE, DefaultValueEncryptor.KEY_ALGORITHM);
|
||||
}
|
||||
|
||||
public static SecretKey makeSecretKeyFromPassword(String password) {
|
||||
byte[] bytes = password.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] passBytes = Arrays.copyOf(bytes, 16);
|
||||
return new SecretKeySpec(passBytes, KEY_ALGORITHM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encryptValue(byte[] value) {
|
||||
try {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
||||
byte[] iv = cipher.getIV();
|
||||
|
||||
ByteArrayOutputStream resultBuffer = new ByteArrayOutputStream();
|
||||
try (CipherOutputStream cipherOut = new CipherOutputStream(resultBuffer, cipher)) {
|
||||
resultBuffer.write(iv);
|
||||
cipherOut.write(value);
|
||||
}
|
||||
return resultBuffer.toByteArray();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error encrypting value", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] decryptValue(byte[] value) {
|
||||
try (InputStream byteStream = new ByteArrayInputStream(value)) {
|
||||
byte[] fileIv = new byte[16];
|
||||
byteStream.read(fileIv);
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(fileIv));
|
||||
|
||||
try (CipherInputStream cipherIn = new CipherInputStream(byteStream, cipher)) {
|
||||
ByteArrayOutputStream resultBuffer = new ByteArrayOutputStream();
|
||||
IOUtils.copy(cipherIn, resultBuffer);
|
||||
return resultBuffer.toByteArray();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error decrypting value", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -37,31 +37,31 @@ public enum DataBaseType {
|
||||
/**
|
||||
* Mariadb
|
||||
**/
|
||||
Mariadb("jdbc:mariadb://%s:%s"),
|
||||
MARIADB("jdbc:mariadb://%s:%s"),
|
||||
/**
|
||||
* DM
|
||||
**/
|
||||
DM("jdbc:dm://%s:%s"),
|
||||
/**
|
||||
* KINGBASE8
|
||||
* KINGBASE
|
||||
**/
|
||||
KINGBASE8("jdbc:kingbase8://%s:%s"),
|
||||
KINGBASE("jdbc:kingbase8://%s:%s"),
|
||||
/**
|
||||
* Presto
|
||||
**/
|
||||
Presto("jdbc:presto://%s:%s"),
|
||||
PRESTO("jdbc:presto://%s:%s"),
|
||||
/**
|
||||
* OceanBase
|
||||
**/
|
||||
OceanBase("jdbc:oceanbase://%s:%s"),
|
||||
OCEANBASE("jdbc:oceanbase://%s:%s"),
|
||||
/**
|
||||
* Hive
|
||||
**/
|
||||
Hive("jdbc:hive2://%s:%s"),
|
||||
HIVE("jdbc:hive2://%s:%s"),
|
||||
/**
|
||||
* ClickHouse
|
||||
**/
|
||||
ClickHouse("jdbc:clickhouse://%s:%s");
|
||||
CLICKHOUSE("jdbc:clickhouse://%s:%s");
|
||||
|
||||
private String urlString;
|
||||
|
||||
@ -76,7 +76,8 @@ public enum DataBaseType {
|
||||
public static DataBaseType matchType(String value) {
|
||||
if (StringUtils.isNotEmpty(value)) {
|
||||
for (DataBaseType dataBase : DataBaseType.values()) {
|
||||
if (dataBase.name().equals(value.toUpperCase())) {
|
||||
//kingbase -> kingbase8
|
||||
if (value.toUpperCase().contains(dataBase.name())) {
|
||||
return dataBase;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2023 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package ai.chat2db.server.web.api.controller.ncx.enums;
|
||||
|
||||
/**
|
||||
* Import/Export constants
|
||||
*/
|
||||
public class ExportConstants {
|
||||
|
||||
public static final String ARCHIVE_FILE_EXT = ".dbp"; //NON-NLS-1
|
||||
public static final String CONFIG_FILE = ".dbeaver"; //NON-NLS-1
|
||||
public static final String CONFIG_DATASOURCE_FILE = "data-sources.json"; //NON-NLS-1
|
||||
public static final String CONFIG_CREDENTIALS_FILE = "credentials-config.json"; //NON-NLS-1
|
||||
public static final String DIR_PROJECTS = "projects"; //NON-NLS-1
|
||||
public static final String DIR_DRIVERS = "drivers"; //NON-NLS-1
|
||||
public static final String DIR_CONNECTIONS = "connections"; //NON-NLS-1
|
||||
public static final String DIR_CONFIGURATION = "configuration"; //NON-NLS-1
|
||||
public static final String GENERIC = "generic"; //NON-NLS-1
|
||||
|
||||
public static final String META_FILENAME = "meta.xml"; //NON-NLS-1
|
||||
|
||||
public static final String TAG_ARCHIVE = "archive"; //NON-NLS-1
|
||||
public static final String TAG_SOURCE = "source";
|
||||
public static final String TAG_PROJECTS = "projects"; //NON-NLS-1
|
||||
public static final String TAG_PROJECT = "project"; //NON-NLS-1
|
||||
public static final String TAG_RESOURCE = "resource"; //NON-NLS-1
|
||||
public static final String TAG_ATTRIBUTE = "attribute"; //NON-NLS-1
|
||||
public static final String TAG_LIBRARIES = "libraries"; //NON-NLS-1
|
||||
|
||||
public static final String ATTR_VERSION = "version"; //NON-NLS-1
|
||||
public static final String ATTR_HOST = "host";
|
||||
public static final String ATTR_ADDRESS = "address";
|
||||
public static final String ATTR_TIME = "time";
|
||||
public static final String ATTR_QUALIFIER = "qualifier"; //NON-NLS-1
|
||||
public static final String ATTR_NAME = "name"; //NON-NLS-1
|
||||
public static final String ATTR_VALUE = "value"; //NON-NLS-1
|
||||
public static final String ATTR_DIRECTORY = "directory"; //NON-NLS-1
|
||||
public static final String ATTR_DESCRIPTION = "description"; //NON-NLS-1
|
||||
public static final String ATTR_CHARSET = "charset"; //NON-NLS-1
|
||||
public static final String ATTR_PATH = "path"; //NON-NLS-1
|
||||
public static final String ATTR_FILE = "file"; //NON-NLS-1
|
||||
|
||||
}
|
@ -3,31 +3,52 @@ package ai.chat2db.server.web.api.controller.ncx.service.impl;
|
||||
import ai.chat2db.server.domain.core.util.DesUtil;
|
||||
import ai.chat2db.server.domain.repository.entity.DataSourceDO;
|
||||
import ai.chat2db.server.domain.repository.mapper.DataSourceMapper;
|
||||
import ai.chat2db.server.tools.common.util.ConfigUtils;
|
||||
import ai.chat2db.server.tools.common.util.ContextUtils;
|
||||
import ai.chat2db.server.web.api.controller.ncx.cipher.CommonCipher;
|
||||
import ai.chat2db.server.web.api.controller.ncx.dbeaver.DefaultValueEncryptor;
|
||||
import ai.chat2db.server.web.api.controller.ncx.enums.DataBaseType;
|
||||
import ai.chat2db.server.web.api.controller.ncx.enums.ExportConstants;
|
||||
import ai.chat2db.server.web.api.controller.ncx.enums.VersionEnum;
|
||||
import ai.chat2db.server.web.api.controller.ncx.factory.CipherFactory;
|
||||
import ai.chat2db.server.web.api.controller.ncx.service.ConverterService;
|
||||
import ai.chat2db.server.web.api.controller.ncx.vo.UploadVO;
|
||||
import ai.chat2db.server.web.api.util.XMLUtils;
|
||||
import ai.chat2db.spi.model.SSHInfo;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import com.alibaba.excel.util.FileUtils;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.w3c.dom.*;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
/**
|
||||
* ConverterServiceImpl
|
||||
@ -51,6 +72,10 @@ public class ConverterServiceImpl implements ConverterService {
|
||||
* xml连接信息开始标志位
|
||||
**/
|
||||
private static final String BEGIN = "#BEGIN#";
|
||||
/**
|
||||
* 密码json的key
|
||||
**/
|
||||
private static final String connection = "#connection";
|
||||
|
||||
@Autowired
|
||||
private DataSourceMapper dataSourceMapper;
|
||||
@ -65,7 +90,6 @@ public class ConverterServiceImpl implements ConverterService {
|
||||
|
||||
@Override
|
||||
public UploadVO uploadFile(File file) {
|
||||
|
||||
UploadVO vo = new UploadVO();
|
||||
try {
|
||||
// List<Map <连接名,Map<属性名,值>>> 要导入的连接
|
||||
@ -117,10 +141,130 @@ public class ConverterServiceImpl implements ConverterService {
|
||||
return vo;
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public UploadVO dbpUploadFile(File file) {
|
||||
return null;
|
||||
UploadVO vo = new UploadVO();
|
||||
Document metaTree;
|
||||
//等待删除的projects
|
||||
List<String> projects = new ArrayList<>();
|
||||
try (ZipFile zipFile = new ZipFile(file, ZipFile.OPEN_READ)) {
|
||||
ZipEntry metaEntry = zipFile.getEntry(ExportConstants.META_FILENAME);
|
||||
if (metaEntry == null) {
|
||||
throw new RuntimeException("Cannot find meta file");
|
||||
}
|
||||
try (InputStream metaStream = zipFile.getInputStream(metaEntry)) {
|
||||
metaTree = XMLUtils.parseDocument(metaStream);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Cannot parse meta file: " + e.getMessage());
|
||||
}
|
||||
Element projectsElement = XMLUtils.getChildElement(metaTree.getDocumentElement(), ExportConstants.TAG_PROJECTS);
|
||||
if (projectsElement != null) {
|
||||
final Collection<Element> projectList = XMLUtils.getChildElementList(projectsElement, ExportConstants.TAG_PROJECT);
|
||||
for (Element projectElement : projectList) {
|
||||
//获取项目名称
|
||||
String projectName = projectElement.getAttribute(ExportConstants.ATTR_NAME);
|
||||
//导入匹配文件目录
|
||||
String config = ConfigUtils.CONFIG_BASE_PATH + File.separator + projectName + File.separator + ExportConstants.CONFIG_FILE;
|
||||
importDbeaverConfig(new File(config),
|
||||
projectElement,
|
||||
//不可替换成File.separator
|
||||
ExportConstants.DIR_PROJECTS + "/" + projectName + "/",
|
||||
zipFile);
|
||||
//加入删除名单
|
||||
projects.add(projectName);
|
||||
//配置的json文件
|
||||
File json = new File(config + File.separator + ExportConstants.CONFIG_DATASOURCE_FILE);
|
||||
JSONObject jsonObject = JSON.parseObject(new FileInputStream(json));
|
||||
JSONObject connections = jsonObject.getJSONObject(ExportConstants.DIR_CONNECTIONS);
|
||||
Set<String> keys = connections.keySet();
|
||||
for (String key : keys) {
|
||||
JSONObject configurations = connections.getJSONObject(key);
|
||||
JSONObject configuration = configurations.getJSONObject(ExportConstants.DIR_CONFIGURATION);
|
||||
//匹配数据库类型
|
||||
String provider = configurations.getString("provider");
|
||||
if (provider.equals(ExportConstants.GENERIC)) {
|
||||
//自定义驱动
|
||||
JSONObject drivers = jsonObject.getJSONObject(ExportConstants.DIR_DRIVERS);
|
||||
//获得驱动id
|
||||
String driverId = configurations.getString("driver");
|
||||
//获得所有generic
|
||||
JSONObject generics = drivers.getJSONObject(provider);
|
||||
//获得自己的驱动
|
||||
JSONObject generic = generics.getJSONObject(driverId);
|
||||
//如果不存在,则不导入
|
||||
if (null == generic) {
|
||||
continue;
|
||||
}
|
||||
//赋值驱动名称,用来确定数据库的类型
|
||||
provider = generic.getString("name");
|
||||
}
|
||||
DataBaseType dataBaseType = DataBaseType.matchType(provider.toUpperCase());
|
||||
DataSourceDO dataSourceDO;
|
||||
//未匹配到数据库类型,如:dbeaver支持自定义驱动等,但chat2DB暂不支持
|
||||
if (null != dataBaseType) {
|
||||
//密码信息
|
||||
File credentials = new File(config + File.separator + ExportConstants.CONFIG_CREDENTIALS_FILE);
|
||||
DefaultValueEncryptor defaultValueEncryptor = new DefaultValueEncryptor(DefaultValueEncryptor.getLocalSecretKey());
|
||||
JSONObject credentialsJson = JSON.parseObject(defaultValueEncryptor.decryptValue(Files.readAllBytes(credentials.toPath())));
|
||||
dataSourceDO = new DataSourceDO();
|
||||
Date dateTime = new Date();
|
||||
dataSourceDO.setGmtCreate(dateTime);
|
||||
dataSourceDO.setGmtModified(dateTime);
|
||||
//插入用户id
|
||||
dataSourceDO.setUserId(ContextUtils.getUserId());
|
||||
dataSourceDO.setAlias(configurations.getString("name"));
|
||||
dataSourceDO.setHost(configuration.getString("host"));
|
||||
dataSourceDO.setPort(configuration.getString("port"));
|
||||
dataSourceDO.setUrl(configuration.getString("url"));
|
||||
//ssh设置为false
|
||||
SSHInfo sshInfo = new SSHInfo();
|
||||
sshInfo.setUse(false);
|
||||
dataSourceDO.setSsh(JSON.toJSONString(sshInfo));
|
||||
if (null != credentialsJson) {
|
||||
JSONObject userInfo = credentialsJson.getJSONObject(key);
|
||||
JSONObject userPassword = userInfo.getJSONObject(connection);
|
||||
dataSourceDO.setUserName(userPassword.getString("user"));
|
||||
DesUtil desUtil = new DesUtil(DesUtil.DES_KEY);
|
||||
String password = userPassword.getString("password");
|
||||
String encryptStr = desUtil.encrypt(Optional.ofNullable(password).orElse(""), "CBC");
|
||||
dataSourceDO.setPassword(encryptStr);
|
||||
}
|
||||
dataSourceDO.setType(dataBaseType.name());
|
||||
dataSourceMapper.insert(dataSourceDO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//删除临时文件
|
||||
FileUtils.delete(file);
|
||||
//删除导入dbeaver时,dbp产生的临时配置文件
|
||||
projects.forEach(v -> FileUtils.delete(new File(ConfigUtils.CONFIG_BASE_PATH + File.separator + v)));
|
||||
return vo;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static void importDbeaverConfig(File resource, Element resourceElement, String containerPath, ZipFile zipFile) {
|
||||
for (Element childElement : XMLUtils.getChildElementList(resourceElement, ExportConstants.TAG_RESOURCE)) {
|
||||
String childName = childElement.getAttribute(ExportConstants.ATTR_NAME);
|
||||
String entryPath = containerPath + childName;
|
||||
ZipEntry resourceEntry = zipFile.getEntry(entryPath);
|
||||
if (resourceEntry == null) {
|
||||
continue;
|
||||
}
|
||||
boolean isDirectory = resourceEntry.isDirectory();
|
||||
if (isDirectory) {
|
||||
File folder = new File(resource.getPath());
|
||||
if (!folder.exists()) {
|
||||
FileUtil.mkdir(folder);
|
||||
}
|
||||
importDbeaverConfig(folder, childElement, entryPath + "/", zipFile);
|
||||
} else {
|
||||
File file = new File(resource.getPath() + File.separator + childName);
|
||||
FileUtil.writeFromStream(zipFile.getInputStream(resourceEntry), file, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@ -154,6 +298,8 @@ public class ConverterServiceImpl implements ConverterService {
|
||||
dataSourceDO.setGmtCreate(dateTime);
|
||||
dataSourceDO.setGmtModified(dateTime);
|
||||
dataSourceDO.setAlias(rootElement.getAttribute("name"));
|
||||
//插入用户id
|
||||
dataSourceDO.setUserId(ContextUtils.getUserId());
|
||||
// 获取子元素 database-info
|
||||
Element databaseInfoElement = (Element) rootElement.getElementsByTagName("database-info").item(0);
|
||||
|
||||
@ -182,6 +328,10 @@ public class ConverterServiceImpl implements ConverterService {
|
||||
|
||||
}
|
||||
}
|
||||
//ssh设置为false
|
||||
SSHInfo sshInfo = new SSHInfo();
|
||||
sshInfo.setUse(false);
|
||||
dataSourceDO.setSsh(JSON.toJSONString(sshInfo));
|
||||
dataSourceDO.setHost(host);
|
||||
dataSourceDO.setPort(port);
|
||||
dataSourceDO.setUrl(jdbcUrl);
|
||||
@ -224,6 +374,8 @@ public class ConverterServiceImpl implements ConverterService {
|
||||
dataSourceDO.setAlias(resultMap.get("ConnectionName"));
|
||||
dataSourceDO.setUserName(resultMap.get("UserName"));
|
||||
dataSourceDO.setType(resultMap.get("ConnType"));
|
||||
//插入用户id
|
||||
dataSourceDO.setUserId(ContextUtils.getUserId());
|
||||
//password 为解密出来的密文,再使用chat2db的加密
|
||||
DesUtil desUtil = new DesUtil(DesUtil.DES_KEY);
|
||||
String encryptStr = desUtil.encrypt(password, "CBC");
|
||||
|
@ -0,0 +1,287 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2023 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package ai.chat2db.server.web.api.util;
|
||||
|
||||
import org.apache.batik.xml.XMLException;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Common XML utils
|
||||
*/
|
||||
public class XMLUtils {
|
||||
|
||||
public static Document parseDocument(String fileName)
|
||||
throws XMLException {
|
||||
return parseDocument(new java.io.File(fileName));
|
||||
}
|
||||
|
||||
public static Document parseDocument(java.io.File file) throws XMLException {
|
||||
try (InputStream is = new FileInputStream(file)) {
|
||||
return parseDocument(new InputSource(is));
|
||||
} catch (IOException e) {
|
||||
throw new XMLException("Error opening file '" + file + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Document parseDocument(InputStream is) throws XMLException {
|
||||
return parseDocument(new InputSource(is));
|
||||
}
|
||||
|
||||
public static Document parseDocument(java.io.Reader is) throws XMLException {
|
||||
return parseDocument(new InputSource(is));
|
||||
}
|
||||
|
||||
public static Document parseDocument(InputSource source) throws XMLException {
|
||||
try {
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
||||
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
DocumentBuilder xmlBuilder = dbf.newDocumentBuilder();
|
||||
return xmlBuilder.parse(source);
|
||||
} catch (Exception er) {
|
||||
throw new XMLException("Error parsing XML document", er);
|
||||
}
|
||||
}
|
||||
|
||||
public static Document createDocument()
|
||||
throws XMLException {
|
||||
try {
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder xmlBuilder = dbf.newDocumentBuilder();
|
||||
return xmlBuilder.newDocument();
|
||||
} catch (Exception er) {
|
||||
throw new XMLException("Error creating XML document", er);
|
||||
}
|
||||
}
|
||||
|
||||
public static Element getChildElement(Element element, String childName) {
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
for (Node node = element.getFirstChild(); node != null; node = node.getNextSibling()) {
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE &&
|
||||
((Element) node).getTagName().equals(childName)) {
|
||||
return (Element) node;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getChildElementBody(Element element, String childName) {
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
for (Node node = element.getFirstChild(); node != null; node = node.getNextSibling()) {
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE &&
|
||||
((Element) node).getTagName().equals(childName)) {
|
||||
return getElementBody((Element) node);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getElementBody( Element element) {
|
||||
return element.getTextContent();
|
||||
}
|
||||
|
||||
// Get list of all child elements of specified node
|
||||
|
||||
public static List<Element> getChildElementList(
|
||||
Element parent,
|
||||
String nodeName) {
|
||||
List<Element> list = new ArrayList<>();
|
||||
if (parent != null) {
|
||||
for (Node node = parent.getFirstChild(); node != null; node = node.getNextSibling()) {
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE &&
|
||||
nodeName.equals(node.getNodeName())) {
|
||||
list.add((Element) node);
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
// Get list of all child elements of specified node
|
||||
|
||||
public static Collection<Element> getChildElementListNS(
|
||||
Element parent,
|
||||
String nsURI) {
|
||||
List<Element> list = new ArrayList<>();
|
||||
if (parent != null) {
|
||||
for (Node node = parent.getFirstChild(); node != null; node = node.getNextSibling()) {
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE &&
|
||||
node.getNamespaceURI().equals(nsURI)) {
|
||||
list.add((Element) node);
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
// Get list of all child elements of specified node
|
||||
public static Collection<Element> getChildElementListNS(
|
||||
Element parent,
|
||||
String nodeName,
|
||||
String nsURI) {
|
||||
List<Element> list = new ArrayList<>();
|
||||
for (Node node = parent.getFirstChild(); node != null; node = node.getNextSibling()) {
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE &&
|
||||
node.getLocalName().equals(nodeName) &&
|
||||
node.getNamespaceURI().equals(nsURI)) {
|
||||
list.add((Element) node);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
// Get list of all child elements of specified node
|
||||
|
||||
public static Collection<Element> getChildElementList(
|
||||
Element parent,
|
||||
String[] nodeNameList) {
|
||||
List<Element> list = new ArrayList<>();
|
||||
for (Node node = parent.getFirstChild(); node != null; node = node.getNextSibling()) {
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
||||
for (int i = 0; i < nodeNameList.length; i++) {
|
||||
if (node.getNodeName().equals(nodeNameList[i])) {
|
||||
list.add((Element) node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
// Find one child element with specified name
|
||||
public static Element findChildElement(
|
||||
Element parent) {
|
||||
for (Node node = parent.getFirstChild(); node != null; node = node.getNextSibling()) {
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
||||
return (Element) node;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Object escapeXml(Object obj) {
|
||||
if (obj == null) {
|
||||
return null;
|
||||
} else if (obj instanceof CharSequence) {
|
||||
return escapeXml((CharSequence) obj);
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static String escapeXml(CharSequence str) {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder res = null;
|
||||
int strLength = str.length();
|
||||
for (int i = 0; i < strLength; i++) {
|
||||
char c = str.charAt(i);
|
||||
String repl = encodeXMLChar(c);
|
||||
if (repl == null) {
|
||||
if (res != null) {
|
||||
res.append(c);
|
||||
}
|
||||
} else {
|
||||
if (res == null) {
|
||||
res = new StringBuilder(str.length() + 5);
|
||||
for (int k = 0; k < i; k++) {
|
||||
res.append(str.charAt(k));
|
||||
}
|
||||
}
|
||||
res.append(repl);
|
||||
}
|
||||
}
|
||||
return res == null ? str.toString() : res.toString();
|
||||
}
|
||||
|
||||
public static boolean isValidXMLChar(char c) {
|
||||
return (c >= 32 || c == '\n' || c == '\r' || c == '\t');
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a char to XML-valid form replacing &,',",<,> with special XML encoding.
|
||||
*
|
||||
* @param ch char to convert
|
||||
* @return XML-encoded text
|
||||
*/
|
||||
public static String encodeXMLChar(char ch) {
|
||||
switch (ch) {
|
||||
case '&':
|
||||
return "&";
|
||||
case '\"':
|
||||
return """;
|
||||
case '\'':
|
||||
return "'";
|
||||
case '<':
|
||||
return "<";
|
||||
case '>':
|
||||
return ">";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static XMLException adaptSAXException(Exception toCatch) {
|
||||
if (toCatch instanceof XMLException) {
|
||||
return (XMLException) toCatch;
|
||||
} else if (toCatch instanceof org.xml.sax.SAXException) {
|
||||
String message = toCatch.getMessage();
|
||||
Exception embedded = ((org.xml.sax.SAXException) toCatch).getException();
|
||||
if (embedded != null && embedded.getMessage() != null && embedded.getMessage().equals(message)) {
|
||||
// Just SAX wrapper - skip it
|
||||
return adaptSAXException(embedded);
|
||||
} else {
|
||||
return new XMLException(
|
||||
message,
|
||||
embedded != null ? adaptSAXException(embedded) : null);
|
||||
}
|
||||
} else {
|
||||
return new XMLException(toCatch.getMessage(), toCatch);
|
||||
}
|
||||
}
|
||||
|
||||
public static Collection<Element> getChildElementList(Element element) {
|
||||
List<Element> children = new ArrayList<>();
|
||||
if (element != null) {
|
||||
for (Node node = element.getFirstChild(); node != null; node = node.getNextSibling()) {
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
||||
children.add((Element) node);
|
||||
}
|
||||
}
|
||||
}
|
||||
return children;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user