|
|
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.JsonNode;
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
import com.fs.common.exception.ServiceException;
|
|
|
import com.fs.common.exception.base.BaseException;
|
|
|
+import com.fs.common.utils.http.SafeHttpUrl;
|
|
|
import com.fs.config.ai.AiHostProper;
|
|
|
import com.fs.fastGpt.domain.FastgptChatVoiceHomo;
|
|
|
import com.fs.fastGpt.service.IFastGptChatMsgService;
|
|
|
@@ -637,8 +638,20 @@ public class AudioUtils {
|
|
|
process = Runtime.getRuntime().exec("taskkill -f -t -im silk_v3_encoder.exe");
|
|
|
*/
|
|
|
// 方法2,除了会弹出弹窗,没什么问题 cmd /c 极为重要,执行完毕后会自动关闭
|
|
|
- process = Runtime.getRuntime().exec("cmd /c start " + path + "silk_v3_encoder.exe " + pcmPath + " " + target + " -tencent");
|
|
|
- process .waitFor();
|
|
|
+ assertSafeLocalPath(pcmPath);
|
|
|
+ assertSafeLocalPath(target);
|
|
|
+ java.util.List<String> silkCmd = new java.util.ArrayList<>();
|
|
|
+ silkCmd.add(path + "silk_v3_encoder.exe");
|
|
|
+ silkCmd.add(pcmPath);
|
|
|
+ silkCmd.add(target);
|
|
|
+ silkCmd.add("-tencent");
|
|
|
+ ProcessBuilder silkBuilder = new ProcessBuilder(silkCmd);
|
|
|
+ silkBuilder.redirectErrorStream(true);
|
|
|
+ process = silkBuilder.start();
|
|
|
+ try (java.io.BufferedReader silkReader = new java.io.BufferedReader(new java.io.InputStreamReader(process.getInputStream()))) {
|
|
|
+ while (silkReader.readLine() != null) { /* drain */ }
|
|
|
+ }
|
|
|
+ process.waitFor();
|
|
|
Thread.sleep(1000);
|
|
|
// 有更好的方法会后续慢慢更新..
|
|
|
} catch (Exception e) {
|
|
|
@@ -658,12 +671,9 @@ public class AudioUtils {
|
|
|
public static void transferPcmSilkSecond(String pcmPath, String target) {
|
|
|
Process process = null;
|
|
|
try {
|
|
|
- // 使用 ProcessBuilder 替代 Runtime.exec 提高可靠性
|
|
|
+ assertSafeLocalPath(pcmPath);
|
|
|
+ assertSafeLocalPath(target);
|
|
|
List<String> command = new ArrayList<>();
|
|
|
- command.add("cmd");
|
|
|
- command.add("/c");
|
|
|
- command.add("start");
|
|
|
- command.add("/wait"); // 等待程序执行完毕才退出
|
|
|
command.add(path + "silk_v3_encoder.exe");
|
|
|
command.add(pcmPath);
|
|
|
command.add(target);
|
|
|
@@ -699,22 +709,26 @@ public class AudioUtils {
|
|
|
public static void transferPcmSilkNew(String pcmPath, String target) {
|
|
|
Process process = null;
|
|
|
try {
|
|
|
+ assertSafeLocalPath(pcmPath);
|
|
|
+ assertSafeLocalPath(target);
|
|
|
List<String> command = new ArrayList<>();
|
|
|
- command.add("cmd");
|
|
|
- command.add("/c");
|
|
|
- command.add("start");
|
|
|
- command.add("/B");
|
|
|
command.add(path + "silk_v3_encoder.exe");
|
|
|
command.add(pcmPath);
|
|
|
command.add(target);
|
|
|
command.add("-tencent");
|
|
|
- ProcessBuilder builder = new ProcessBuilder();
|
|
|
- builder.command(command);
|
|
|
- Process p = builder.start();
|
|
|
- p.waitFor();
|
|
|
- p.destroy();
|
|
|
+ ProcessBuilder builder = new ProcessBuilder(command);
|
|
|
+ builder.redirectErrorStream(true);
|
|
|
+ process = builder.start();
|
|
|
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
|
|
|
+ while (reader.readLine() != null) { /* drain */ }
|
|
|
+ }
|
|
|
+ process.waitFor();
|
|
|
} catch (Exception e) {
|
|
|
e.printStackTrace();
|
|
|
+ } finally {
|
|
|
+ if (process != null) {
|
|
|
+ process.destroy();
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
/**
|
|
|
@@ -727,45 +741,52 @@ public class AudioUtils {
|
|
|
InputStream inputStream = null;
|
|
|
FileOutputStream outputStream = null;
|
|
|
try {
|
|
|
- // 创建 HTTP 连接
|
|
|
- URL url = new URL(fileUrl);
|
|
|
+ // SSRF 防护:协议/域名白名单 + 禁私网 IP
|
|
|
+ SafeHttpUrl.validateFetchUrl(fileUrl);
|
|
|
+ URL url = SafeHttpUrl.toValidatedUrl(fileUrl);
|
|
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
|
|
- // 设置Referer请求头
|
|
|
-// connection.setRequestProperty("Referer", "cos.his.cdwjyyh.com");
|
|
|
+ connection.setInstanceFollowRedirects(false);
|
|
|
+ connection.setConnectTimeout(10000);
|
|
|
+ connection.setReadTimeout(30000);
|
|
|
connection.setRequestMethod("GET");
|
|
|
connection.connect();
|
|
|
|
|
|
- // 检查是否成功连接
|
|
|
- if (connection.getResponseCode() != 200) {
|
|
|
- throw new ServiceException("无法下载音频文件,HTTP 响应码:" + connection.getResponseCode());
|
|
|
+ int code = connection.getResponseCode();
|
|
|
+ if (code != 200) {
|
|
|
+ throw new ServiceException("无法下载音频文件,HTTP 响应码:" + code);
|
|
|
}
|
|
|
|
|
|
- // 获取输入流
|
|
|
inputStream = connection.getInputStream();
|
|
|
|
|
|
- // 创建临时文件,并指定存放地址
|
|
|
String tempFileName = "temp_" + UUID.randomUUID() + "_" + getFileExtension(fileUrl);
|
|
|
File destinationDirectory = new File(destinationDir);
|
|
|
|
|
|
- // 参照 transferAudioSilk 方法,同步确保目录创建的线程安全
|
|
|
synchronized (AudioUtils.class) {
|
|
|
if (!destinationDirectory.exists()) {
|
|
|
destinationDirectory.mkdirs();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 将文件保存到指定路径
|
|
|
File tempFile = new File(destinationDirectory, tempFileName);
|
|
|
|
|
|
- // 写入文件
|
|
|
outputStream = new FileOutputStream(tempFile);
|
|
|
byte[] buffer = new byte[8192];
|
|
|
int bytesRead;
|
|
|
+ long total = 0;
|
|
|
+ long max = SafeHttpUrl.maxBytes();
|
|
|
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
|
|
+ total += bytesRead;
|
|
|
+ if (total > max) {
|
|
|
+ throw new ServiceException("下载文件超过大小限制");
|
|
|
+ }
|
|
|
outputStream.write(buffer, 0, bytesRead);
|
|
|
}
|
|
|
|
|
|
return tempFile;
|
|
|
+ } catch (ServiceException e) {
|
|
|
+ throw e;
|
|
|
+ } catch (IllegalArgumentException e) {
|
|
|
+ throw new ServiceException(e.getMessage());
|
|
|
} catch (Exception e) {
|
|
|
e.printStackTrace();
|
|
|
} finally {
|
|
|
@@ -963,4 +984,16 @@ public class AudioUtils {
|
|
|
return byteOutput.toByteArray();
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ private static void assertSafeLocalPath(String p) {
|
|
|
+ if (p == null || p.isEmpty()) {
|
|
|
+ throw new IllegalArgumentException("路径为空");
|
|
|
+ }
|
|
|
+ if (p.indexOf(0) >= 0 || p.contains("..") || p.contains("|") || p.contains("&")
|
|
|
+ || p.contains(";") || p.contains("`") || p.contains("$(")
|
|
|
+ || p.indexOf('\n') >= 0 || p.indexOf('\r') >= 0
|
|
|
+ || p.contains("\"") || p.contains("'")) {
|
|
|
+ throw new IllegalArgumentException("非法路径参数");
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|