Merge pull request #13255 from dataease/pr@dev-v2@fixds

Pr@dev v2@fixds
This commit is contained in:
xuwei-fit2cloud 2024-11-11 19:26:01 +08:00 committed by GitHub
commit 217da936cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 305 additions and 156 deletions

View File

@ -128,17 +128,20 @@ public class ChartDataServer implements ChartDataApi {
request.setHeader(dsHeader); request.setHeader(dsHeader);
request.setExcelTypes(dsTypes); request.setExcelTypes(dsTypes);
} }
for (Object[] objects : tableRow) { if (CollectionUtils.isNotEmpty(tableRow)) {
for (int i = 0; i < viewDTO.getXAxis().size(); i++) { for (Object[] objects : tableRow) {
if (viewDTO.getXAxis().get(i).getDeType().equals(DeTypeConstants.DE_INT) || viewDTO.getXAxis().get(i).getDeType().equals(DeTypeConstants.DE_FLOAT)) { for (int i = 0; i < viewDTO.getXAxis().size(); i++) {
try { if (viewDTO.getXAxis().get(i).getDeType().equals(DeTypeConstants.DE_INT) || viewDTO.getXAxis().get(i).getDeType().equals(DeTypeConstants.DE_FLOAT)) {
objects[i] = valueFormatter(BigDecimal.valueOf(Double.valueOf(objects[i].toString())), viewDTO.getXAxis().get(i).getFormatterCfg()); try {
} catch (Exception ignore) { objects[i] = valueFormatter(BigDecimal.valueOf(Double.valueOf(objects[i].toString())), viewDTO.getXAxis().get(i).getFormatterCfg());
} catch (Exception ignore) {
}
} }
} }
} }
} }
request.setDetails(tableRow); request.setDetails(tableRow);
request.setData(chartViewInfo.getData());
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@ -483,6 +483,23 @@ public class DatasourceServer implements DatasourceApi {
return getDatasourceDTOById(datasourceId, true); return getDatasourceDTOById(datasourceId, true);
} }
@Override
public DatasourceDTO getSimpleDs(Long datasourceId) throws DEException {
CoreDatasource datasource = datasourceMapper.selectById(datasourceId);
if (datasource == null) {
DEException.throwException("不存在的数据源!");
}
if (datasource.getType().equalsIgnoreCase("api")) {
datasource.setConfiguration("[]");
} else {
datasource.setConfiguration("");
}
datasource.setConfiguration("");
DatasourceDTO datasourceDTO = new DatasourceDTO();
BeanUtils.copyBean(datasourceDTO, datasource);
return datasourceDTO;
}
@Override @Override
public DatasourceDTO get(Long datasourceId) throws DEException { public DatasourceDTO get(Long datasourceId) throws DEException {
return getDatasourceDTOById(datasourceId, false); return getDatasourceDTOById(datasourceId, false);
@ -1132,8 +1149,12 @@ public class DatasourceServer implements DatasourceApi {
params.add(apiDefinition); params.add(apiDefinition);
} }
} }
datasourceDTO.setApiConfigurationStr(new String(Base64.getEncoder().encode(Objects.requireNonNull(JsonUtil.toJSONString(apiDefinitionListWithStatus)).toString().getBytes()))); if(CollectionUtils.isNotEmpty(params)){
datasourceDTO.setParamsStr(new String(Base64.getEncoder().encode(Objects.requireNonNull(JsonUtil.toJSONString(params)).toString().getBytes()))); datasourceDTO.setParamsStr(RsaUtils.symmetricEncrypt(JsonUtil.toJSONString(params).toString()));
}
if(CollectionUtils.isNotEmpty(apiDefinitionListWithStatus)){
datasourceDTO.setApiConfigurationStr(RsaUtils.symmetricEncrypt(JsonUtil.toJSONString(apiDefinitionListWithStatus).toString()));
}
if (success == apiDefinitionList.size()) { if (success == apiDefinitionList.size()) {
datasourceDTO.setStatus("Success"); datasourceDTO.setStatus("Success");
} else { } else {
@ -1147,7 +1168,6 @@ public class DatasourceServer implements DatasourceApi {
TaskDTO taskDTO = new TaskDTO(); TaskDTO taskDTO = new TaskDTO();
BeanUtils.copyBean(taskDTO, coreDatasourceTask); BeanUtils.copyBean(taskDTO, coreDatasourceTask);
datasourceDTO.setSyncSetting(taskDTO); datasourceDTO.setSyncSetting(taskDTO);
CoreDatasourceTask task = datasourceTaskServer.selectByDSId(datasourceDTO.getId()); CoreDatasourceTask task = datasourceTaskServer.selectByDSId(datasourceDTO.getId());
if (task != null) { if (task != null) {
datasourceDTO.setLastSyncTime(task.getStartTime()); datasourceDTO.setLastSyncTime(task.getStartTime());
@ -1157,13 +1177,12 @@ public class DatasourceServer implements DatasourceApi {
Provider provider = ProviderFactory.getProvider(datasourceDTO.getType()); Provider provider = ProviderFactory.getProvider(datasourceDTO.getType());
provider.hidePW(datasourceDTO); provider.hidePW(datasourceDTO);
} }
} }
if (datasourceDTO.getType().equalsIgnoreCase(DatasourceConfiguration.DatasourceType.Excel.toString())) { if (datasourceDTO.getType().equalsIgnoreCase(DatasourceConfiguration.DatasourceType.Excel.toString())) {
datasourceDTO.setFileName(ExcelUtils.getFileName(datasource)); datasourceDTO.setFileName(ExcelUtils.getFileName(datasource));
datasourceDTO.setSize(ExcelUtils.getSize(datasource)); datasourceDTO.setSize(ExcelUtils.getSize(datasource));
} }
datasourceDTO.setConfiguration(new String(Base64.getEncoder().encode(datasourceDTO.getConfiguration().getBytes()))); datasourceDTO.setConfiguration(RsaUtils.symmetricEncrypt(datasourceDTO.getConfiguration()));
datasourceDTO.setCreator(coreUserManage.getUserName(Long.valueOf(datasourceDTO.getCreateBy()))); datasourceDTO.setCreator(coreUserManage.getUserName(Long.valueOf(datasourceDTO.getCreateBy())));
return datasourceDTO; return datasourceDTO;
} }

View File

@ -5,9 +5,12 @@ import io.dataease.datasource.dao.auto.entity.CoreDeEngine;
import io.dataease.datasource.dao.auto.mapper.CoreDeEngineMapper; import io.dataease.datasource.dao.auto.mapper.CoreDeEngineMapper;
import io.dataease.datasource.manage.EngineManage; import io.dataease.datasource.manage.EngineManage;
import io.dataease.datasource.provider.CalciteProvider; import io.dataease.datasource.provider.CalciteProvider;
import io.dataease.exception.DEException;
import io.dataease.extensions.datasource.dto.DatasourceDTO; import io.dataease.extensions.datasource.dto.DatasourceDTO;
import io.dataease.utils.AuthUtils;
import io.dataease.utils.BeanUtils; import io.dataease.utils.BeanUtils;
import io.dataease.utils.IDUtils; import io.dataease.utils.IDUtils;
import io.dataease.utils.RsaUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -30,33 +33,44 @@ public class EngineServer implements EngineApi {
@Override @Override
public DatasourceDTO getEngine() { public DatasourceDTO getEngine() {
if (!AuthUtils.getUser().getUserId().equals(1L)) {
DEException.throwException("非管理员,无权访问!");
}
DatasourceDTO datasourceDTO = new DatasourceDTO(); DatasourceDTO datasourceDTO = new DatasourceDTO();
List<CoreDeEngine> deEngines = deEngineMapper.selectList(null); List<CoreDeEngine> deEngines = deEngineMapper.selectList(null);
if (CollectionUtils.isEmpty(deEngines)) { if (CollectionUtils.isEmpty(deEngines)) {
return datasourceDTO; return datasourceDTO;
} }
return BeanUtils.copyBean(datasourceDTO, deEngines.get(0)); BeanUtils.copyBean(datasourceDTO, deEngines.get(0));
datasourceDTO.setConfiguration(RsaUtils.symmetricEncrypt(datasourceDTO.getConfiguration()));
return datasourceDTO;
} }
@Override @Override
public void save(DatasourceDTO datasourceDTO) { public void save(DatasourceDTO datasourceDTO) {
if (!AuthUtils.getUser().getUserId().equals(1L)) {
DEException.throwException("非管理员,无权访问!");
}
if (StringUtils.isNotEmpty(datasourceDTO.getConfiguration())) { if (StringUtils.isNotEmpty(datasourceDTO.getConfiguration())) {
datasourceDTO.setConfiguration(new String(Base64.getDecoder().decode(datasourceDTO.getConfiguration()))); datasourceDTO.setConfiguration(new String(Base64.getDecoder().decode(datasourceDTO.getConfiguration())));
} }
CoreDeEngine coreDeEngine = new CoreDeEngine(); CoreDeEngine coreDeEngine = new CoreDeEngine();
BeanUtils.copyBean(coreDeEngine, datasourceDTO); BeanUtils.copyBean(coreDeEngine, datasourceDTO);
if(coreDeEngine.getId() == null){ if (coreDeEngine.getId() == null) {
coreDeEngine.setId(IDUtils.snowID()); coreDeEngine.setId(IDUtils.snowID());
datasourceDTO.setId(coreDeEngine.getId()); datasourceDTO.setId(coreDeEngine.getId());
deEngineMapper.insert(coreDeEngine); deEngineMapper.insert(coreDeEngine);
}else { } else {
deEngineMapper.updateById(coreDeEngine); deEngineMapper.updateById(coreDeEngine);
} }
calciteProvider.update(datasourceDTO); calciteProvider.update(datasourceDTO);
} }
@Override @Override
public void validate(DatasourceDTO datasourceDTO) throws Exception{ public void validate(DatasourceDTO datasourceDTO) throws Exception {
if (!AuthUtils.getUser().getUserId().equals(1L)) {
DEException.throwException("非管理员,无权访问!");
}
CoreDeEngine coreDeEngine = new CoreDeEngine(); CoreDeEngine coreDeEngine = new CoreDeEngine();
BeanUtils.copyBean(coreDeEngine, datasourceDTO); BeanUtils.copyBean(coreDeEngine, datasourceDTO);
coreDeEngine.setConfiguration(new String(Base64.getDecoder().decode(coreDeEngine.getConfiguration()))); coreDeEngine.setConfiguration(new String(Base64.getDecoder().decode(coreDeEngine.getConfiguration())));
@ -65,6 +79,9 @@ public class EngineServer implements EngineApi {
@Override @Override
public void validateById(Long id) throws Exception { public void validateById(Long id) throws Exception {
if (!AuthUtils.getUser().getUserId().equals(1L)) {
DEException.throwException("非管理员,无权访问!");
}
engineManage.validate(deEngineMapper.selectById(id)); engineManage.validate(deEngineMapper.selectById(id));
} }

View File

@ -655,16 +655,18 @@ public class ExportCenterManage implements BaseExportApi {
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
if (CollectionUtils.isEmpty(request.getMultiInfo())) { if (CollectionUtils.isEmpty(request.getMultiInfo())) {
List<Object[]> details = request.getDetails(); if(request.getViewInfo().getType().equalsIgnoreCase("chart-mix-dual-line")){
Integer[] excelTypes = request.getExcelTypes();
details.add(0, request.getHeader());
ViewDetailField[] detailFields = request.getDetailFields();
Object[] header = request.getHeader();
//明细sheet }else {
Sheet detailsSheet = wb.createSheet("数据"); List<Object[]> details = request.getDetails();
Integer[] excelTypes = request.getExcelTypes();
details.add(0, request.getHeader());
ViewDetailField[] detailFields = request.getDetailFields();
Object[] header = request.getHeader();
Sheet detailsSheet = wb.createSheet("数据");
ChartDataServer.setExcelData(detailsSheet, cellStyle, header, details, detailFields, excelTypes);
}
ChartDataServer.setExcelData(detailsSheet, cellStyle, header, details, detailFields, excelTypes);
} else { } else {
//多个sheet //多个sheet
for (int i = 0; i < request.getMultiInfo().size(); i++) { for (int i = 0; i < request.getMultiInfo().size(); i++) {

View File

@ -23,6 +23,13 @@ public class RestIndexController {
return RsaUtils.publicKey(); return RsaUtils.publicKey();
} }
@GetMapping("/symmetricKey")
@ResponseBody
public String symmetricKey() {
return RsaUtils.generateSymmetricKey();
}
@GetMapping("/model") @GetMapping("/model")
@ResponseBody @ResponseBody
public boolean model() { public boolean model() {

View File

@ -19,7 +19,7 @@ import java.util.List;
@Component @Component
public class LinkInterceptor implements HandlerInterceptor { public class LinkInterceptor implements HandlerInterceptor {
private final static String whiteListText = "/user/ipInfo, /apisix/check, /datasetData/enumValue, /datasetData/enumValueObj, /datasetData/getFieldTree, /dekey, /share/validate, /sysParameter/queryOnlineMap, /chartData/innerExportDetails"; private final static String whiteListText = "/user/ipInfo, /apisix/check, /datasetData/enumValue, /datasetData/enumValueObj, /datasetData/getFieldTree, /dekey, /symmetricKey, /share/validate, /sysParameter/queryOnlineMap, /chartData/innerExportDetails";
@Override @Override

View File

@ -155,6 +155,8 @@ export const getById = (id: number) => request.get({ url: '/datasource/get/' + i
export const getHidePwById = (id: number) => request.get({ url: '/datasource/hidePw/' + id }) export const getHidePwById = (id: number) => request.get({ url: '/datasource/hidePw/' + id })
export const getSimpleDs = (id: number) => request.get({ url: '/datasource/getSimpleDs/' + id })
export const uploadFile = async (data): Promise<IResponse> => { export const uploadFile = async (data): Promise<IResponse> => {
return request return request
.post({ .post({

View File

@ -4,6 +4,8 @@ export const loginApi = data => request.post({ url: '/login/localLogin', data })
export const queryDekey = () => request.get({ url: 'dekey' }) export const queryDekey = () => request.get({ url: 'dekey' })
export const querySymmetricKey = () => request.get({ url: 'symmetricKey' })
export const modelApi = () => request.get({ url: 'model' }) export const modelApi = () => request.get({ url: 'model' })
export const platformLoginApi = origin => request.post({ url: '/login/platformLogin/' + origin }) export const platformLoginApi = origin => request.post({ url: '/login/platformLogin/' + origin })

View File

@ -40,3 +40,15 @@ export const rsaEncryp = word => {
crypt.setKey(pk) crypt.setKey(pk)
return crypt.encrypt(word) return crypt.encrypt(word)
} }
export const symmetricDecrypt = (data, keyStr) => {
const iv = CryptoJS.enc.Utf8.parse('0000000000000000')
const key = CryptoJS.enc.Base64.parse(keyStr)
const decodedCiphertext = CryptoJS.enc.Base64.parse(data)
const decrypted = CryptoJS.AES.decrypt({ ciphertext: decodedCiphertext }, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
})
return decrypted.toString(CryptoJS.enc.Utf8)
}

View File

@ -10,6 +10,8 @@ import { cloneDeep } from 'lodash-es'
import { getDeEngine } from '@/api/datasource' import { getDeEngine } from '@/api/datasource'
import { CustomPassword } from '@/components/custom-password' import { CustomPassword } from '@/components/custom-password'
import { Base64 } from 'js-base64' import { Base64 } from 'js-base64'
import { querySymmetricKey } from '@/api/login'
import { symmetricDecrypt } from '@/utils/encryption'
const { t } = useI18n() const { t } = useI18n()
const dialogVisible = ref(false) const dialogVisible = ref(false)
const loadingInstance = ref(null) const loadingInstance = ref(null)
@ -149,45 +151,47 @@ const defaultInfo = {
} }
const nodeInfo = reactive(cloneDeep(defaultInfo)) const nodeInfo = reactive(cloneDeep(defaultInfo))
const edit = () => { const edit = () => {
getDeEngine() querySymmetricKey().then(response => {
.then(res => { getDeEngine()
let { .then(res => {
name, let {
createBy, name,
id, createBy,
createTime, id,
creator, createTime,
type, creator,
pid, type,
configuration, pid,
syncSetting, configuration,
fileName, syncSetting,
size, fileName,
description, size,
lastSyncTime description,
} = res.data lastSyncTime
if (configuration) { } = res.data
configuration = JSON.parse(configuration) if (configuration) {
} configuration = JSON.parse(symmetricDecrypt(configuration, response.data))
Object.assign(nodeInfo, { }
name, Object.assign(nodeInfo, {
pid, name,
description, pid,
fileName, description,
size, fileName,
createTime, size,
creator, createTime,
createBy, creator,
id, createBy,
type, id,
configuration, type,
syncSetting, configuration,
lastSyncTime syncSetting,
lastSyncTime
})
}) })
}) .finally(() => {
.finally(() => { dialogVisible.value = true
dialogVisible.value = true })
}) })
} }
const basicForm = ref() const basicForm = ref()

View File

@ -42,6 +42,8 @@ import InfoTemplate from '@/views/system/common/InfoTemplate.vue'
import { dsTypes } from '@/views/visualized/data/datasource/form/option' import { dsTypes } from '@/views/visualized/data/datasource/form/option'
import { getDeEngine } from '@/api/datasource' import { getDeEngine } from '@/api/datasource'
import request from '@/config/axios' import request from '@/config/axios'
import { querySymmetricKey } from '@/api/login'
import { symmetricDecrypt } from '@/utils/encryption'
const { t } = useI18n() const { t } = useI18n()
const typeMap = dsTypes.reduce((pre, next) => { const typeMap = dsTypes.reduce((pre, next) => {
pre[next.type] = next.name pre[next.type] = next.name
@ -54,82 +56,82 @@ const infoTemplateTime = ref()
const templateList = ref<SettingRecord[]>([]) const templateList = ref<SettingRecord[]>([])
const templateListTime = ref<SettingRecord[]>([]) const templateListTime = ref<SettingRecord[]>([])
const getEngine = () => { const getEngine = () => {
getDeEngine().then(res => { querySymmetricKey().then(response => {
let { id, type, configuration } = res.data getDeEngine().then(res => {
if (configuration) { let { id, type, configuration } = res.data
configuration = JSON.parse(configuration) if (configuration) {
} configuration = JSON.parse(symmetricDecrypt(configuration, response.data))
nodeInfoId = id
templateListTime.value = [
{
pkey: 'datasource.initial_pool_size',
pval: configuration?.initialPoolSize || 5,
type: '',
sort: 0
},
{
pkey: 'datasource.min_pool_size',
pval: configuration?.minPoolSize || 5,
type: '',
sort: 0
},
{
pkey: 'datasource.max_pool_size',
pval: configuration?.maxPoolSize || 5,
type: '',
sort: 0
},
{
pkey: 'datasource.query_timeout',
pval: `${configuration?.queryTimeout || 30}${t('common.second')}`,
type: '',
sort: 0
} }
] nodeInfoId = id
templateListTime.value = [
{
pkey: 'datasource.initial_pool_size',
pval: configuration?.initialPoolSize || 5,
type: '',
sort: 0
},
{
pkey: 'datasource.min_pool_size',
pval: configuration?.minPoolSize || 5,
type: '',
sort: 0
},
{
pkey: 'datasource.max_pool_size',
pval: configuration?.maxPoolSize || 5,
type: '',
sort: 0
},
{
pkey: 'datasource.query_timeout',
pval: `${configuration?.queryTimeout || 30}${t('common.second')}`,
type: '',
sort: 0
}
]
templateList.value = [ templateList.value = [
{ {
pkey: t('system.engine_type'), pkey: t('system.engine_type'),
pval: typeMap[type], pval: typeMap[type],
type: '', type: '',
sort: 0 sort: 0
}, },
{ {
pkey: 'datasource.host', pkey: 'datasource.host',
pval: configuration?.host, pval: configuration?.host,
type: '', type: '',
sort: 0 sort: 0
}, },
{ {
pkey: 'datasource.port', pkey: 'datasource.port',
pval: configuration?.port, pval: configuration?.port,
type: '', type: '',
sort: 0 sort: 0
}, },
{ {
pkey: 'datasource.data_base', pkey: 'datasource.data_base',
pval: configuration?.dataBase, pval: configuration?.dataBase,
type: '', type: '',
sort: 0 sort: 0
}, },
{ {
pkey: 'datasource.user_name', pkey: 'datasource.user_name',
pval: configuration?.username, pval: configuration?.username,
type: '', type: '',
sort: 0 sort: 0
}, },
{ {
pkey: 'datasource.extra_params', pkey: 'datasource.extra_params',
pval: configuration?.extraParams, pval: configuration?.extraParams,
type: '', type: '',
sort: 0 sort: 0
} }
] ]
nextTick(() => { nextTick(() => {
infoTemplate.value.init() infoTemplate.value.init()
infoTemplateTime.value.init() infoTemplateTime.value.init()
})
}) })
}) })
} }

View File

@ -42,7 +42,13 @@ import { HandleMore } from '@/components/handle-more'
import { Icon } from '@/components/icon-custom' import { Icon } from '@/components/icon-custom'
import { fieldType } from '@/utils/attr' import { fieldType } from '@/utils/attr'
import { useEmitt } from '@/hooks/web/useEmitt' import { useEmitt } from '@/hooks/web/useEmitt'
import { getHidePwById, listSyncRecord, uploadFile, perDeleteDatasource } from '@/api/datasource' import {
getHidePwById,
listSyncRecord,
uploadFile,
perDeleteDatasource,
getSimpleDs
} from '@/api/datasource'
import CreatDsGroup from './form/CreatDsGroup.vue' import CreatDsGroup from './form/CreatDsGroup.vue'
import type { Tree } from '../dataset/form/CreatDsGroup.vue' import type { Tree } from '../dataset/form/CreatDsGroup.vue'
import { previewData, getById } from '@/api/datasource' import { previewData, getById } from '@/api/datasource'
@ -81,6 +87,8 @@ import { useEmbedded } from '@/store/modules/embedded'
import { XpackComponent } from '@/components/plugin' import { XpackComponent } from '@/components/plugin'
import { iconFieldMap } from '@/components/icon-group/field-list' import { iconFieldMap } from '@/components/icon-group/field-list'
import { iconDatasourceMap } from '@/components/icon-group/datasource-list' import { iconDatasourceMap } from '@/components/icon-group/datasource-list'
import { querySymmetricKey } from '@/api/login'
import { symmetricDecrypt } from '@/utils/encryption'
const route = useRoute() const route = useRoute()
const interactiveStore = interactiveStoreWithOut() const interactiveStore = interactiveStoreWithOut()
interface Field { interface Field {
@ -458,6 +466,7 @@ const saveDsFolder = (params, successCb, finallyCb, cmd) => {
const dsLoading = ref(false) const dsLoading = ref(false)
const mounted = ref(false) const mounted = ref(false)
const symmetricKey = ref('')
const listDs = () => { const listDs = () => {
rawDatasourceList.value = [] rawDatasourceList.value = []
@ -550,7 +559,11 @@ const handleNodeClick = data => {
dsListTree.value.setCurrentKey(null) dsListTree.value.setCurrentKey(null)
return return
} }
return getHidePwById(data.id).then(res => { let method = getHidePwById
if (data.weight < 7) {
method = getSimpleDs
}
return method(data.id).then(res => {
let { let {
name, name,
createBy, createBy,
@ -570,13 +583,13 @@ const handleNodeClick = data => {
enableDataFill enableDataFill
} = res.data } = res.data
if (configuration) { if (configuration) {
configuration = JSON.parse(Base64.decode(configuration)) configuration = JSON.parse(symmetricDecrypt(configuration, symmetricKey.value))
}
if (apiConfigurationStr) {
apiConfigurationStr = JSON.parse(Base64.decode(apiConfigurationStr))
} }
if (paramsStr) { if (paramsStr) {
paramsStr = JSON.parse(Base64.decode(paramsStr)) paramsStr = JSON.parse(symmetricDecrypt(paramsStr, symmetricKey.value))
}
if (apiConfigurationStr) {
apiConfigurationStr = JSON.parse(symmetricDecrypt(apiConfigurationStr, symmetricKey.value))
} }
Object.assign(nodeInfo, { Object.assign(nodeInfo, {
name, name,
@ -697,13 +710,13 @@ const editDatasource = (editType?: number) => {
enableDataFill enableDataFill
} = res.data } = res.data
if (configuration) { if (configuration) {
configuration = JSON.parse(Base64.decode(configuration)) configuration = JSON.parse(symmetricDecrypt(configuration, symmetricKey.value))
} }
if (paramsStr) { if (paramsStr) {
paramsStr = JSON.parse(Base64.decode(paramsStr)) paramsStr = JSON.parse(symmetricDecrypt(paramsStr, symmetricKey.value))
} }
if (apiConfigurationStr) { if (apiConfigurationStr) {
apiConfigurationStr = JSON.parse(Base64.decode(apiConfigurationStr)) apiConfigurationStr = JSON.parse(symmetricDecrypt(apiConfigurationStr, symmetricKey.value))
} }
let datasource = reactive<Node>(cloneDeep(defaultInfo)) let datasource = reactive<Node>(cloneDeep(defaultInfo))
Object.assign(datasource, { Object.assign(datasource, {
@ -762,13 +775,13 @@ const handleCopy = async data => {
lastSyncTime lastSyncTime
} = res.data } = res.data
if (configuration) { if (configuration) {
configuration = JSON.parse(Base64.decode(configuration)) configuration = JSON.parse(symmetricDecrypt(configuration, symmetricKey.value))
} }
if (paramsStr) { if (paramsStr) {
paramsStr = JSON.parse(Base64.decode(paramsStr)) paramsStr = JSON.parse(symmetricDecrypt(paramsStr, symmetricKey.value))
} }
if (apiConfigurationStr) { if (apiConfigurationStr) {
apiConfigurationStr = JSON.parse(Base64.decode(apiConfigurationStr)) apiConfigurationStr = JSON.parse(symmetricDecrypt(apiConfigurationStr, symmetricKey.value))
} }
let datasource = reactive<Node>(cloneDeep(defaultInfo)) let datasource = reactive<Node>(cloneDeep(defaultInfo))
Object.assign(datasource, { Object.assign(datasource, {
@ -901,6 +914,7 @@ const operation = (cmd: string, data: Tree, nodeType: string) => {
const handleClick = (tabName: TabPaneName) => { const handleClick = (tabName: TabPaneName) => {
switch (tabName) { switch (tabName) {
case 'config': case 'config':
tableData.value = []
listDatasourceTables({ datasourceId: nodeInfo.id }).then(res => { listDatasourceTables({ datasourceId: nodeInfo.id }).then(res => {
tabList.value = res.data.map(ele => { tabList.value = res.data.map(ele => {
const { name, tableName } = ele const { name, tableName } = ele
@ -979,6 +993,9 @@ onMounted(() => {
if (opt && opt === 'create') { if (opt && opt === 'create') {
datasourceEditor.value.init(null, null) datasourceEditor.value.init(null, null)
} }
querySymmetricKey().then(res => {
symmetricKey.value = res.data
})
}) })
const sideTreeStatus = ref(true) const sideTreeStatus = ref(true)
@ -1433,7 +1450,9 @@ const getMenuList = (val: boolean) => {
}}</BaseInfoItem> }}</BaseInfoItem>
</el-col> </el-col>
</el-row> </el-row>
<template v-if="!['Excel', 'API', 'es'].includes(nodeInfo.type)"> <template
v-if="!['Excel', 'API', 'es'].includes(nodeInfo.type) && nodeInfo.weight >= 7"
>
<el-row :gutter="24" v-show="nodeInfo.configuration.urlType !== 'jdbcUrl'"> <el-row :gutter="24" v-show="nodeInfo.configuration.urlType !== 'jdbcUrl'">
<el-col :span="12"> <el-col :span="12">
<BaseInfoItem :label="t('datasource.host')">{{ <BaseInfoItem :label="t('datasource.host')">{{
@ -1564,7 +1583,7 @@ const getMenuList = (val: boolean) => {
</el-row> </el-row>
</template> </template>
</template> </template>
<template v-if="['es'].includes(nodeInfo.type)"> <template v-if="['es'].includes(nodeInfo.type) && nodeInfo.weight >= 7">
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="12"> <el-col :span="12">
<BaseInfoItem :label="t('datasource.datasource_url')">{{ <BaseInfoItem :label="t('datasource.datasource_url')">{{
@ -1576,7 +1595,7 @@ const getMenuList = (val: boolean) => {
</template> </template>
</BaseInfoContent> </BaseInfoContent>
<BaseInfoContent <BaseInfoContent
v-if="nodeInfo.type === 'API'" v-if="nodeInfo.type === 'API' && nodeInfo.weight >= 7"
v-slot="slotProps" v-slot="slotProps"
:name="t('datasource.data_table')" :name="t('datasource.data_table')"
> >
@ -1633,7 +1652,7 @@ const getMenuList = (val: boolean) => {
</el-button> </el-button>
</BaseInfoContent> </BaseInfoContent>
<BaseInfoContent <BaseInfoContent
v-if="nodeInfo.type === 'API'" v-if="nodeInfo.type === 'API' && nodeInfo.weight >= 7"
v-slot="slotProps" v-slot="slotProps"
:name="t('dataset.update_setting')" :name="t('dataset.update_setting')"
:time="(nodeInfo.lastSyncTime as string)" :time="(nodeInfo.lastSyncTime as string)"

View File

@ -5,6 +5,7 @@ import lombok.Data;
import java.io.Serial; import java.io.Serial;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* @Author wangjiahao * @Author wangjiahao
@ -26,4 +27,6 @@ public class ChartExcelRequest extends ChartExcelRequestInner {
private String downloadType; private String downloadType;
private Map<String, Object> data;
} }

View File

@ -87,16 +87,21 @@ public interface DatasourceApi {
@Operation(summary = "删除") @Operation(summary = "删除")
void delete(@PathVariable("datasourceId") Long datasourceId) throws DEException; void delete(@PathVariable("datasourceId") Long datasourceId) throws DEException;
@DePermit({"#p0+':read'"}) @DePermit({"#p0+':manage'"})
@GetMapping("/get/{datasourceId}") @GetMapping("/get/{datasourceId}")
@Operation(summary = "数据源详情") @Operation(summary = "数据源详情")
DatasourceDTO get(@PathVariable("datasourceId") Long datasourceId) throws DEException; DatasourceDTO get(@PathVariable("datasourceId") Long datasourceId) throws DEException;
@DePermit({"#p0+':read'"}) @DePermit({"#p0+':manage'"})
@GetMapping("/hidePw/{datasourceId}") @GetMapping("/hidePw/{datasourceId}")
@Operation(summary = "数据源详情") @Operation(summary = "数据源详情")
DatasourceDTO hidePw(@PathVariable("datasourceId") Long datasourceId) throws DEException; DatasourceDTO hidePw(@PathVariable("datasourceId") Long datasourceId) throws DEException;
@DePermit({"#p0+':read'"})
@GetMapping("/getSimpleDs/{datasourceId}")
@Operation(summary = "数据源详情")
DatasourceDTO getSimpleDs(@PathVariable("datasourceId") Long datasourceId) throws DEException;
@PostMapping("/getTableField") @PostMapping("/getTableField")
@Operation(summary = "获取表字段") @Operation(summary = "获取表字段")

View File

@ -8,9 +8,11 @@ import io.dataease.rsa.manage.RsaManage;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
@ -176,7 +178,7 @@ public class RsaUtils {
return pk + separator + aesKey; return pk + separator + aesKey;
} }
private static final String IV_KEY = "0000000000000000"; public static final String IV_KEY = "0000000000000000";
private static String generateAesKey() { private static String generateAesKey() {
return RandomStringUtils.randomAlphanumeric(16); return RandomStringUtils.randomAlphanumeric(16);
@ -200,4 +202,53 @@ public class RsaUtils {
} }
} }
private static final String ALGORITHM = "AES";
public static String symmetricKey = null;
private static final int KEY_SIZE = 128;
public static String generateSymmetricKey() {
try {
if (StringUtils.isEmpty(symmetricKey)) {
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
keyGenerator.init(KEY_SIZE, new SecureRandom());
SecretKey secretKey = keyGenerator.generateKey();
symmetricKey = Base64.getEncoder().encodeToString(secretKey.getEncoded());
}
return symmetricKey;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String symmetricEncrypt(String data) {
try {
byte[] iv = IV_KEY.getBytes(StandardCharsets.UTF_8);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode(generateSymmetricKey()), ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] ciphertext = cipher.doFinal(data.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(ciphertext);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String symmetricDecrypt(String data) {
try {
byte[] iv = IV_KEY.getBytes(StandardCharsets.UTF_8);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode(generateSymmetricKey()), ALGORITHM);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] decodedCiphertext = Base64.getDecoder().decode(data);
byte[] decryptedText = cipher.doFinal(decodedCiphertext);
return new String(decryptedText, "UTF-8");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
} }

View File

@ -24,6 +24,7 @@ public class WhitelistUtils {
"/login/localLogin", "/login/localLogin",
"/apisix/check", "/apisix/check",
"/dekey", "/dekey",
"/symmetricKey",
"/index.html", "/index.html",
"/model", "/model",
"/xpackModel", "/xpackModel",