文章摘要(AI生成)
本文介绍了在使用生产环境或者开源项目时,配置文件中的密码需要加密的背景和现状,以及目前存在的问题。针对这一问题,提出了开发一个插件的目标,该插件可以支持密码加密和配置文件解密验证。功能设计包括明文密钥加密、加解密配置文件对照和插件选项卡设置。安全算法方面,需要实现各种加密算法,并定义一个安全实例来提供不同算法的加解入口。最后,参考了Java官方文档中关于安全算法实现的要求。总体而言,本文提供了一个解决配置文件加密问题的解决方案,并详细说明了开发目标、功能设计和安全算法实现的步骤。
背景&现状
在使用生产环境或者开源项目时,项目中的配置文件application.properties
或者application.yml
中的配置密码通常需要加密。现有的对配置文件进行加密的项目有jasypt-spring-boot
, 但是在使用过程中加密的配置文件我们会发现以下问题:
- 需要通过单测用例或者在线加密网站进行手动加密在手动替换配置文件的原有明文密码
- 替换过程中如果出现失误,只能通过服务启动来验证,如果是商业服务会造成一定的线上损失
基于以上的问题,我们可以通过在IDEA中开发插件,来支持密码加密和配置文件解密验证
开发目标
主要为了解决我们在使用jasypt
中遇到的两个难点,方便我们更好的使用jasypt
对配置文件进行加密
功能设计
我们可以对本次需求做一下简单的交互流程图设计:
这样我们至少知道本插件至少有三个功能:
- 明文密钥加密功能:对选中的明文密钥进行加密,并使用加密密钥替换明文密钥
- 加解密配置文件对照:对选中配置文件中的ENC加密串进行解密,弹出对比框,对比加密和解密后的配置文件
- 插件选项卡:配置插件的加密算法和加密密钥
详细设计
安全算法
这里我们需要对各种加密算法进行实现,我们可以定义一个安全实例,来提供不同安全算法的加解入口:
public interface SecurityInstance {
EncryptResult encrypt(String src, String key, String index) throws Exception;
DecryptResult decrypt(String src, String key, String index) throws Exception;
}
而安全算法我们可以参考java 官方文档:
安全算法实现要求
本节定义 Java SE 实现的安全算法要求。安全算法要求旨在提高使用这些算法的 Java SE 实现和应用程序的互操作性。
注意:本节中的要求并不是算法强度或安全性的衡量标准。例如,密码分析的最新进展发现 DESede(三重 DES)密码算法的强度存在弱点。您有责任确定算法是否满足您的应用程序的安全要求。
此版本 Java SE 平台的每个实现都必须支持下表中指定的算法。这些要求不适用于第三方提供商。请参阅您的实现的发行文档,了解是否支持任何其他算法。
文本加密
这里我们添加一个文本右键菜单栏选项:
<action id="encrypt-action" class="tech.shiker.enccore.EncryptEncAction" text="ENC Encrypt"
description="Encrypt a string">
<add-to-group group-id="EditorPopupMenu" anchor="first"/>
</action>
EditorPopupMenu
是IDEA编辑选项卡的选项组,我们这里将我们的加密选项添加到选项卡的第一个选项
而在加密实现时我们可以采用如下方式实现:
@Override
public void actionPerformed(AnActionEvent e) {
Project project = e.getProject();
if (project != null) {
// 获取用户当前选择的文本
Editor editor = e.getData(CommonDataKeys.EDITOR);
if (editor != null) {
SelectionModel selectionModel = editor.getSelectionModel();
String selectedText = selectionModel.getSelectedText();
if (selectedText != null && !selectedText.isEmpty()) {
// 进行加密操作
EncryptResult encryptResult = encrypt(selectedText);
if (encryptResult.isEncryptError()) {
Messages.showMessageDialog(project, encryptResult.message(), SecurityConstant.ENC_DECRYPT_TITLE, Messages.getInformationIcon());
}
// 获取选中文本的开始和结束偏移量
int startOffset = selectionModel.getSelectionStart();
int endOffset = selectionModel.getSelectionEnd();
// 获取文档对象并替换选中文本
Document document = editor.getDocument();
WriteCommandAction.runWriteCommandAction(project, () ->
document.replaceString(startOffset, endOffset, String.format(SecurityConstant.ENCRYPT_RESULT, encryptResult.encryptStr())));
} else {
Messages.showInfoMessage(project, SecurityConstant.ENCRYPT_NULL_MESSAGE, SecurityConstant.ENC_DECRYPT_TITLE);
}
}
}
}
文件解密
文件解密时,我们需要用户右键编辑选项卡顶部,然后弹出解密选项卡,那么我们需要把选项添加到EditorPopupMenu
中
<action id="encrypt-action" class="tech.shiker.enccore.EncryptEncAction" text="ENC Encrypt"
description="Encrypt a string">
<add-to-group group-id="EditorPopupMenu" anchor="first"/>
</action>
同时解密的操作也可以用如下方式实现:
@Override
public void actionPerformed(AnActionEvent e) {
Project project = e.getProject();
if (project != null) {
VirtualFile virtualFile = e.getData(CommonDataKeys.VIRTUAL_FILE);
if (virtualFile != null && isYamlOrPropertiesFile(virtualFile)) {
try {
if("Off".equals(EncSettingState.getInstance().isHtmlView)){
processFileV2(project, virtualFile);
}else{
processFile(virtualFile);
}
} catch (Exception ex) {
Messages.showMessageDialog(ex.getMessage(), SecurityConstant.ENC_DECRYPT_TITLE, Messages.getInformationIcon());
}
} else {
Messages.showMessageDialog(SecurityConstant.UN_SUPPORT_MESSAGE, SecurityConstant.ENC_DECRYPT_TITLE, Messages.getInformationIcon());
}
}
}
这里,我处理文件采用了两种模式,一种是通过html渲染的方式弹出对话框来对比解密前后的配置文件:
另一种是采用IDEA自带的文本对比实现方式:
如果采用前者,那么我们需要自己通过swing来实现html的渲染。并且在解密时需要对原有的文本串添加颜色区分;
如果采用后者,那么我们在实现时只需要几行代码就可以搞定:
DiffContentFactory contentFactory = DiffContentFactory.getInstance();
SimpleDiffRequest diffRequest = new SimpleDiffRequest("ENC Compare",
contentFactory.create(text),
contentFactory.create(decryptedContent.toString()),
"Source file", "Decrypted file");
DiffManager.getInstance().showDiff(project, diffRequest);
除了SimpleDiffRequest
,IntelliJ IDEA还提供了其他几种进行文本比较的方式,包括:
- FileDiffRequest:用于比较两个文件之间的差异。您可以使用
FileDiffRequest
来比较两个文件的内容,并在比较结果中显示差异。 - EditorDiffRequest:用于比较两个编辑器中的文本。您可以使用
EditorDiffRequest
来比较两个编辑器中的文本,并在比较结果中显示差异。 - ContentDiffRequest:用于比较两个内容之间的差异。您可以使用
ContentDiffRequest
来比较两个内容实例(例如字符串、文档等)之间的差异,并在比较结果中显示差异。
选项卡设置
在拓展点中添加对AppSettingsConfigurable
的拓展:
<extensions defaultExtensionNs="com.intellij">
<applicationConfigurable parentId="tools" instance="tech.shiker.config.EncToolConfigurable"
id="org.intellij.sdk.settings.AppSettingsConfigurable"
displayName="ENC Decrypt Tool"/>
<applicationService serviceImplementation="tech.shiker.config.EncSettingState"/>
</extensions>
然后我们在代码中进行实现:
public class EncToolConfigurable implements Configurable {
}
这样插件开发便大功告成了!
评论区