Merge remote-tracking branch 'origin/dev-1.0' into dev-1.1

# Conflicts:
#	src/main/resources/db/migration/R__AZ_sys_i18n.sql
This commit is contained in:
shizhendong
2024-10-21 15:42:31 +08:00
7 changed files with 114 additions and 39 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"),
// GIT

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;
@@ -64,48 +67,56 @@ 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());
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 {
ApkInfo apkInfo = apkUtil.parseXapk(destination.getPath());
if (T.ObjectUtil.isNull(apkInfo)) {
throw new ASWException(RCode.PACKAGE_FILE_TYPE_ERROR);
}
entity.setVersion(apkInfo.getSdkVersion());
entity.setIdentifier(apkInfo.getPackageName());
}
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

@@ -1,9 +1,14 @@
package net.geedge.asw.module.app.util;
import cn.hutool.core.io.FileUtil;
import cn.hutool.log.Log;
import net.geedge.asw.common.util.Constants;
import net.geedge.asw.common.util.T;
import java.io.*;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class ApkUtil {
@@ -60,6 +65,9 @@ public class ApkUtil {
while ((temp = bufferedReader.readLine()) != null) {
setApkInfoProperty(apkInfo, temp);
}
if (T.StrUtil.isBlank(apkInfo.getPackageName()) || T.StrUtil.isBlank(apkInfo.getVersionName())) {
return null;
}
return apkInfo;
} catch (IOException e) {
log.error(e, "[parseApk] [error] [path: {}]", apkPath);
@@ -73,6 +81,43 @@ public class ApkUtil {
}
}
public ApkInfo parseXapk(String xapkPath) {
InputStream inputStream = null;
BufferedReader reader = null;
File tempFile = null;
try {
ZipFile zipFile = new ZipFile(T.FileUtil.file(xapkPath));
ZipEntry entry = zipFile.getEntry("manifest.json");
inputStream = zipFile.getInputStream(entry);
StringBuilder manifestJson = new StringBuilder();
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"));
tempFile = T.FileUtil.file(Constants.TEMP_PATH, packageFile.getName());
FileUtil.writeBytes(zipFile.getInputStream(packageFile).readAllBytes(), tempFile);
ApkInfo apkInfo = this.parseApk(tempFile.getPath());
if (apkInfo == null) {
return null;
}
if (!T.BooleanUtil.and(apkInfo.getVersionName().equals(T.MapUtil.getStr(manifest, "version_name")),
apkInfo.getPackageName().equals(T.MapUtil.getStr(manifest, "package_name")))) {
return null;
}
return apkInfo;
} catch (Exception e) {
log.error(e, "[parseXapk] [error] [path: {}]", xapkPath);
return null;
} finally {
T.FileUtil.del(tempFile);
T.IoUtil.close(inputStream);
T.IoUtil.close(reader);
}
}
private void setApkInfoProperty(ApkInfo apkInfo, String source) {
if (source.startsWith(APPLICATION)) {
String[] rs = source.split("( icon=')|'");

View File

@@ -32,7 +32,8 @@ public class JobController {
public R list(@PathVariable("workspaceId") String workspaceId,
@RequestParam Map<String, Object> params) {
T.VerifyUtil.is(params).notNull()
.and(T.MapUtil.getStr(params, "workspaceId")).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
.and(workspaceId).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY);
params.put("workspaceId", workspaceId);
Page page = jobService.queryList(params);
return R.ok(page);
}

View File

@@ -2,6 +2,7 @@ package net.geedge.asw.module.workspace.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.geedge.asw.common.util.ASWException;
import net.geedge.asw.common.util.RCode;
@@ -50,9 +51,22 @@ public class WorkspaceMemberServiceImpl extends ServiceImpl<WorkspaceMemberDao,
@Override
@Transactional(rollbackFor = Exception.class)
public List<WorkspaceMemberEntity> updateMember(String workspaceId, List<WorkspaceMemberEntity> memberList) {
validateInfo(workspaceId, memberList);
workspaceMemberService.remove(new LambdaQueryWrapper<WorkspaceMemberEntity>().eq(WorkspaceMemberEntity::getWorkspaceId, workspaceId));
workspaceMemberService.saveBatch(memberList);
List<WorkspaceMemberEntity> list = this.list(new LambdaQueryWrapper<WorkspaceMemberEntity>().eq(WorkspaceMemberEntity::getWorkspaceId, workspaceId));
List<String> userIds = list.stream().map(x -> x.getUserId()).toList();
for (WorkspaceMemberEntity member : memberList) {
String userId = member.getUserId();
if (userIds.contains(userId)) {
this.update(new LambdaUpdateWrapper<WorkspaceMemberEntity>()
.eq(WorkspaceMemberEntity::getUserId, userId)
.eq(WorkspaceMemberEntity::getWorkspaceId, workspaceId)
.set(WorkspaceMemberEntity::getRoleId, member.getRoleId()));
}else {
member.setWorkspaceId(workspaceId);
member.setCreateTimestamp(System.currentTimeMillis());
member.setCreateUserId(StpUtil.getLoginIdAsString());
this.save(member);
}
}
Map params = T.MapUtil.builder("workspaceId", workspaceId).build();
List<WorkspaceMemberEntity> memberEntityList = workspaceMemberService.queryList(params);
return memberEntityList;

View File

@@ -29,7 +29,7 @@ INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('4003', 'package_delete', 'buttons.delete', '4000', 'button', '', '', '', 3, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('4004', 'package_download', 'buttons.download', '4000', 'button', '', '', '', 4, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('5000', 'jobs', 'overall.jobs', '0', 'menu', '', '/jobs', 'asw-icon icon-Jobs', 4, 1722478572000, 0);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('5000', 'jobs', 'overall.jobs', '0', 'menu', '', '/jobs', 'asw-icon icon-Jobs', 4, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('5001', 'job_view', 'buttons.view', '5000', 'button', '', '', '', 1, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('5002', 'job_add', 'buttons.add', '5000', 'button', '', '', '', 2, 1722478572000, 1);
INSERT INTO `sys_menu` (`id`, `name`, `i18n`, `pid`, `type`, `perms`, `route`, `icon`, `order`, `create_timestamp`, `state`) VALUES ('5003', 'job_delete', 'buttons.delete', '5000', 'button', '', '', '', 3, 1722478572000, 1);