fix:ASW-99 修复 package 上传缺少必要的文件格式校验

This commit is contained in:
zhangshuai
2024-10-15 14:06:03 +08:00
parent dc5f2ebb74
commit 95e950ecd0
4 changed files with 73 additions and 35 deletions

View File

@@ -104,7 +104,10 @@ public class Constants {
public static final Map<String, WebSocketSession> ENV_TERMINAL_WEBSOCKET_SESSION = T.MapUtil.newHashMap();
/**
* Android package type
*/
public static final List<String> ANDROID_PACKAGE_TYPE_LIST = T.ListUtil.of("xapk", "apk");
public static final String EMPTY_FILE_MD5 = "d41d8cd98f00b204e9800998ecf8427e";
}

View File

@@ -55,6 +55,7 @@ public enum RCode {
// Package
PACKAGE_ID_CANNOT_EMPTY(202001, "package id cannot be empty"),
PACKAGE_DESCRIPTION_CANNOT_EMPTY(202002, "package description cannot be empty"),
PACKAGE_FILE_TYPE_ERROR(202003, "package invalid file"),
// Runner

View File

@@ -1,9 +1,12 @@
package net.geedge.asw.module.app.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.log.Log;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.geedge.asw.common.util.ASWException;
import net.geedge.asw.common.util.Constants;
import net.geedge.asw.common.util.RCode;
import net.geedge.asw.common.util.T;
import net.geedge.asw.module.app.dao.PackageDao;
@@ -22,10 +25,14 @@ import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.BufferedReader;
import java.io.File;
import java.nio.file.Path;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@Service
public class PackageServiceImpl extends ServiceImpl<PackageDao, PackageEntity> implements IPackageService {
@@ -64,48 +71,72 @@ public class PackageServiceImpl extends ServiceImpl<PackageDao, PackageEntity> i
}
@Override
@Transactional(rollbackFor = Exception.class)
public PackageEntity savePackage(String workspaceId, String description, Resource fileResource) {
String pkgId = T.StrUtil.uuid();
String filename = fileResource.getFilename();
String suffix = T.FileUtil.extName(filename);
suffix = T.StrUtil.emptyToDefault(suffix, "apk");
if (!Constants.ANDROID_PACKAGE_TYPE_LIST.contains(suffix)) {
throw new ASWException(RCode.PACKAGE_FILE_TYPE_ERROR);
}
String saveFileName = pkgId + "." + suffix;
File destination = T.FileUtil.file(PkgConstant.APK_FILES_DIR, saveFileName);
PackageEntity entity = new PackageEntity();
ApkUtil apkUtil = new ApkUtil();
//apkUtil.setAaptToolPath(Path.of(T.WebPathUtil.getRootPath(), "lib", "aapt").toString());
apkUtil.setAaptToolPath("D:\\Desktop\\asw\\aapt.exe");
try {
String pkgId = T.StrUtil.uuid();
entity.setId(pkgId);
entity.setName(fileResource.getFilename());
entity.setDescription(T.StrUtil.emptyToDefault(description, ""));
// 默认安卓
entity.setPlatform(PkgConstant.Platform.ANDROID.getValue());
entity.setWorkspaceId(workspaceId);
entity.setCreateUserId(StpUtil.getLoginIdAsString());
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
entity.setCreateTimestamp(System.currentTimeMillis());
entity.setUpdateTimestamp(System.currentTimeMillis());
byte[] bytes = fileResource.getInputStream().readAllBytes();
entity.setSize((long) bytes.length);
// path
String fileExtName = T.StrUtil.emptyToDefault(T.FileUtil.extName(fileResource.getFilename()), "pcap");
String saveFileName = pkgId + "." + fileExtName;
File destination = T.FileUtil.file(PkgConstant.APK_FILES_DIR, saveFileName);
FileUtils.copyInputStreamToFile(fileResource.getInputStream(), destination);
entity.setPath(destination.getPath());
// parse
try {
ApkUtil apkUtil = new ApkUtil();
apkUtil.setAaptToolPath(Path.of(T.WebPathUtil.getRootPath(), "lib", "aapt").toString());
ApkInfo apkInfo = apkUtil.parseApk(entity.getPath());
if (suffix.equals("apk")) {
// parse
ApkInfo apkInfo = apkUtil.parseApk(destination.getPath());
if (T.ObjectUtil.isNull(apkInfo)) {
throw new ASWException(RCode.PACKAGE_FILE_TYPE_ERROR);
}
entity.setVersion(apkInfo.getVersionName());
entity.setIdentifier(apkInfo.getPackageName());
} catch (Exception e) {
log.error(e, "[savePackage] [parse error] [file: {}]", fileResource.getFilename());
} else {
ZipFile zipFile = new ZipFile(destination);
ZipEntry entry = zipFile.getEntry("manifest.json");
InputStream inputStream = zipFile.getInputStream(entry);
StringBuilder manifestJson = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
manifestJson.append(line).append("\n");
}
Map manifest = T.JSONUtil.toBean(manifestJson.toString(), Map.class);
ZipEntry packageFile = zipFile.getEntry(T.StrUtil.concat(true,T.MapUtil.getStr(manifest, "package_name"),".apk"));
File temp = T.FileUtil.file(Constants.TEMP_PATH, packageFile.getName());
FileUtil.writeBytes(zipFile.getInputStream(packageFile).readAllBytes(), temp);
ApkInfo apkInfo = apkUtil.parseApk(temp.getPath());
String versionName = apkInfo.getVersionName();
String packageName = apkInfo.getPackageName();
if (!T.BooleanUtil.and(versionName.equals(T.MapUtil.getStr(manifest, "version_name")), packageName.equals(T.MapUtil.getStr(manifest, "package_name")))){
throw new ASWException(RCode.PACKAGE_FILE_TYPE_ERROR);
}
entity.setVersion(versionName);
entity.setIdentifier(packageName);
}
this.save(entity);
} catch (Exception e) {
log.error(e, "[savePackage] [error] [file: {}]", fileResource.getFilename());
log.error(e, "[savePackage] [save package error] [file: {}]", fileResource.getFilename());
FileUtil.del(destination);
throw new ASWException(RCode.PACKAGE_FILE_TYPE_ERROR);
}
entity.setId(pkgId);
entity.setName(fileResource.getFilename());
entity.setDescription(T.StrUtil.emptyToDefault(description, ""));
entity.setPlatform(PkgConstant.Platform.ANDROID.getValue());
entity.setWorkspaceId(workspaceId);
entity.setCreateUserId(StpUtil.getLoginIdAsString());
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
entity.setCreateTimestamp(System.currentTimeMillis());
entity.setUpdateTimestamp(System.currentTimeMillis());
entity.setSize(destination.length());
entity.setPath(destination.getPath());
this.save(entity);
return entity;
}

View File

@@ -139,5 +139,8 @@ INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (231, '302002', 'PLAYBOOK_NAME_DUPLICATE', '剧本名称重复', 'zh', '', 'admin', 1724030366000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (232, '601005', 'ENVIRONMENT_ID_CANNOT_EMPTY', 'environment id cannot be empty', 'en', '', 'admin', 1724030366000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (233, '601005', 'ENVIRONMENT_ID_CANNOT_EMPTY', '环境 id 不能为空', 'zh', '', 'admin', 1724030366000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (234, '202003', 'PACKAGE_FILE_TYPE_ERROR', 'package invalid file', 'en', '', 'admin', 1724030366000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (235, '202003', 'PACKAGE_FILE_TYPE_ERROR', '无效安装包文件', 'zh', '', 'admin', 1724030366000);
SET FOREIGN_KEY_CHECKS = 1;