diff --git a/src/main/java/net/geedge/asw/module/app/controller/PackageController.java b/src/main/java/net/geedge/asw/module/app/controller/PackageController.java index a7f2ebf..38001b8 100644 --- a/src/main/java/net/geedge/asw/module/app/controller/PackageController.java +++ b/src/main/java/net/geedge/asw/module/app/controller/PackageController.java @@ -1,65 +1,71 @@ package net.geedge.asw.module.app.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import jakarta.servlet.http.HttpServletResponse; import net.geedge.asw.common.util.R; import net.geedge.asw.common.util.RCode; +import net.geedge.asw.common.util.ResponseUtil; import net.geedge.asw.common.util.T; import net.geedge.asw.module.app.entity.PackageEntity; import net.geedge.asw.module.app.service.IPackageService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; import java.util.Map; @RestController -@RequestMapping("/api/v1/package") +@RequestMapping("/api/v1/workspace") public class PackageController { @Autowired private IPackageService packageService; - @GetMapping("/{id}") - public R detail(@PathVariable("id") String id) { - PackageEntity entity = packageService.getById(id); + @GetMapping("/{workspaceId}/package/{id}") + public R detail(@PathVariable("workspaceId") String workspaceId, @PathVariable("id") String id) { + PackageEntity entity = packageService.queryInfo(id); return R.ok().putData("record", entity); } - @GetMapping - public R list(@RequestParam Map params) { - T.VerifyUtil.is(params).notNull() - .and(T.MapUtil.getStr(params, "workspaceId")).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY); + @GetMapping("/{workspaceId}/package") + public R list(@PathVariable("workspaceId") String workspaceId, @RequestParam Map params) { + // workspaceId + params = T.MapUtil.defaultIfEmpty(params, new HashMap<>()); + params.put("workspaceId", workspaceId); + Page page = packageService.queryList(params); return R.ok(page); } - @PostMapping - public R add(@RequestBody PackageEntity entity) { - T.VerifyUtil.is(entity).notNull() - .and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY) - .and(entity.getDescription()).notEmpty(RCode.PACKAGE_DESCRIPTION_CANNOT_EMPTY) - .and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY); + @PostMapping("/{workspaceId}/package") + public R add(@PathVariable(value = "workspaceId", required = true) String workspaceId, + @RequestParam(value = "description", required = false) String description, + @RequestParam(value = "file") MultipartFile file) { - PackageEntity pkgEntity = packageService.savePackage(entity); - return R.ok().putData("id", pkgEntity.getId()); + PackageEntity entity = packageService.savePackage(workspaceId, description, file.getResource()); + return R.ok().putData("record", entity); } - @PutMapping - public R update(@RequestBody PackageEntity entity) { - T.VerifyUtil.is(entity).notNull() - .and(entity.getId()).notEmpty(RCode.ID_CANNOT_EMPTY) - .and(entity.getName()).notEmpty(RCode.NAME_CANNOT_EMPTY) - .and(entity.getDescription()).notEmpty(RCode.PACKAGE_DESCRIPTION_CANNOT_EMPTY) - .and(entity.getWorkspaceId()).notEmpty(RCode.WORKSPACE_ID_CANNOT_EMPTY); - - PackageEntity pkgEntity = packageService.updatePackage(entity); - return R.ok().putData("id", pkgEntity.getId()); - } - - @DeleteMapping + @DeleteMapping("/{workspaceId}/package") public R delete(String[] ids) { T.VerifyUtil.is(ids).notEmpty(); packageService.removePackage(T.ListUtil.of(ids)); return R.ok(); } + @GetMapping("/{workspaceId}/package/{id}/download") + public void download(@PathVariable("workspaceId") String workspaceId, + @PathVariable("id") String id, + HttpServletResponse response) throws IOException { + PackageEntity entity = packageService.getById(id); + T.VerifyUtil.is(entity).notNull(RCode.SYS_RECORD_NOT_FOUND); + + File pkgFile = T.FileUtil.file(entity.getPath()); + ResponseUtil.downloadFile(response, MediaType.APPLICATION_OCTET_STREAM_VALUE, entity.getName(), T.FileUtil.readBytes(pkgFile)); + } + } \ No newline at end of file diff --git a/src/main/java/net/geedge/asw/module/app/entity/PackageEntity.java b/src/main/java/net/geedge/asw/module/app/entity/PackageEntity.java index 6d878c9..eadeb9b 100644 --- a/src/main/java/net/geedge/asw/module/app/entity/PackageEntity.java +++ b/src/main/java/net/geedge/asw/module/app/entity/PackageEntity.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; +import net.geedge.asw.module.sys.entity.SysUserEntity; @Data @TableName("package") @@ -13,11 +14,13 @@ public class PackageEntity { @TableId(type = IdType.ASSIGN_UUID) private String id; private String name; - private String logo; + private String icon; private String description; private String platform; private String version; private String identifier; + private String path; + private Long size; private Long createTimestamp; private Long updateTimestamp; @@ -27,6 +30,9 @@ public class PackageEntity { private String workspaceId; @TableField(exist = false) - private String workbookId; + private SysUserEntity createUser; + + @TableField(exist = false) + private SysUserEntity updateUser; } \ No newline at end of file diff --git a/src/main/java/net/geedge/asw/module/app/service/IPackageService.java b/src/main/java/net/geedge/asw/module/app/service/IPackageService.java index c86eb03..6741569 100644 --- a/src/main/java/net/geedge/asw/module/app/service/IPackageService.java +++ b/src/main/java/net/geedge/asw/module/app/service/IPackageService.java @@ -3,17 +3,18 @@ package net.geedge.asw.module.app.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import net.geedge.asw.module.app.entity.PackageEntity; +import org.springframework.core.io.Resource; import java.util.List; import java.util.Map; public interface IPackageService extends IService{ + PackageEntity queryInfo(String id); + Page queryList(Map params); - PackageEntity savePackage(PackageEntity entity); - - PackageEntity updatePackage(PackageEntity entity); + PackageEntity savePackage(String workspaceId, String description, Resource fileResource); void removePackage(List ids); } diff --git a/src/main/java/net/geedge/asw/module/app/service/impl/PackageServiceImpl.java b/src/main/java/net/geedge/asw/module/app/service/impl/PackageServiceImpl.java index d36084a..d4a0ea5 100644 --- a/src/main/java/net/geedge/asw/module/app/service/impl/PackageServiceImpl.java +++ b/src/main/java/net/geedge/asw/module/app/service/impl/PackageServiceImpl.java @@ -1,30 +1,60 @@ package net.geedge.asw.module.app.service.impl; import cn.dev33.satoken.stp.StpUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +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.RCode; import net.geedge.asw.common.util.T; import net.geedge.asw.module.app.dao.PackageDao; import net.geedge.asw.module.app.entity.PackageEntity; import net.geedge.asw.module.app.service.IPackageService; +import net.geedge.asw.module.app.util.ApkInfo; +import net.geedge.asw.module.app.util.ApkUtil; +import net.geedge.asw.module.app.util.PkgConstant; +import net.geedge.asw.module.sys.entity.SysUserEntity; +import net.geedge.asw.module.sys.service.ISysUserService; import net.geedge.asw.module.workbook.service.IWorkbookResourceService; import net.geedge.asw.module.workbook.util.WorkbookConstant; +import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.io.File; +import java.nio.file.Path; import java.util.List; import java.util.Map; @Service public class PackageServiceImpl extends ServiceImpl implements IPackageService { + private final static Log log = Log.get(); + + @Autowired + private ISysUserService sysUserService; + @Autowired private IWorkbookResourceService workbookResourceService; + @Override + public PackageEntity queryInfo(String id) { + PackageEntity entity = this.getById(id); + T.VerifyUtil.is(entity).notNull(RCode.SYS_RECORD_NOT_FOUND); + + // user + SysUserEntity createUser = sysUserService.getById(entity.getCreateUserId()); + SysUserEntity updateUser = sysUserService.getById(entity.getUpdateUserId()); + + createUser.setPwd(null); + updateUser.setPwd(null); + + entity.setCreateUser(createUser); + entity.setUpdateUser(updateUser); + return entity; + } + @Override public Page queryList(Map params) { Page page = T.PageUtil.getPage(params); @@ -34,55 +64,63 @@ public class PackageServiceImpl extends ServiceImpl i } @Override - @Transactional(rollbackFor = Exception.class) - public PackageEntity savePackage(PackageEntity entity) { - PackageEntity one = this.getOne(new LambdaQueryWrapper() - .eq(PackageEntity::getWorkspaceId, entity.getWorkspaceId()) - .eq(PackageEntity::getName, entity.getName())); - if (T.ObjectUtil.isNotNull(one)) { - throw ASWException.builder().rcode(RCode.SYS_DUPLICATE_RECORD).build(); + public PackageEntity savePackage(String workspaceId, String description, Resource fileResource) { + PackageEntity entity = new PackageEntity(); + 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()); + entity.setVersion(apkInfo.getVersionName()); + entity.setIdentifier(apkInfo.getPackageName()); + } catch (Exception e) { + log.error(e, "[savePackage] [parse error] [file: {}]", fileResource.getFilename()); + } + + this.save(entity); + } catch (Exception e) { + log.error(e, "[savePackage] [error] [file: {}]", fileResource.getFilename()); } - - entity.setCreateTimestamp(System.currentTimeMillis()); - entity.setUpdateTimestamp(System.currentTimeMillis()); - entity.setCreateUserId(StpUtil.getLoginIdAsString()); - entity.setUpdateUserId(StpUtil.getLoginIdAsString()); - - // save - this.save(entity); - - // workbook resource - workbookResourceService.saveResource(entity.getWorkbookId(), entity.getId(), WorkbookConstant.ResourceType.PACKAGE.getValue()); - return entity; - } - - @Override - @Transactional(rollbackFor = Exception.class) - public PackageEntity updatePackage(PackageEntity entity) { - PackageEntity one = this.getOne(new LambdaQueryWrapper() - .eq(PackageEntity::getWorkspaceId, entity.getWorkspaceId()) - .eq(PackageEntity::getName, entity.getName()) - .ne(PackageEntity::getId, entity.getId())); - if (T.ObjectUtil.isNotNull(one)) { - throw ASWException.builder().rcode(RCode.SYS_DUPLICATE_RECORD).build(); - } - - entity.setUpdateTimestamp(System.currentTimeMillis()); - entity.setUpdateUserId(StpUtil.getLoginIdAsString()); - - // update - this.updateById(entity); - - // workbook resource - workbookResourceService.saveResource(entity.getWorkbookId(), entity.getId(), WorkbookConstant.ResourceType.PACKAGE.getValue()); return entity; } @Override @Transactional(rollbackFor = Exception.class) public void removePackage(List ids) { - // remove - this.removeBatchByIds(ids); + for (String id : ids) { + PackageEntity entity = this.getById(id); + // remove file + T.FileUtil.del(entity.getPath()); + + // remove + this.removeById(id); + } + // workbook resource workbookResourceService.removeResource(ids, WorkbookConstant.ResourceType.PACKAGE.getValue()); } diff --git a/src/main/java/net/geedge/asw/module/app/util/ApkInfo.java b/src/main/java/net/geedge/asw/module/app/util/ApkInfo.java new file mode 100644 index 0000000..e4da08b --- /dev/null +++ b/src/main/java/net/geedge/asw/module/app/util/ApkInfo.java @@ -0,0 +1,169 @@ +package net.geedge.asw.module.app.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ApkInfo { + + public static final String APPLICATION_ICON_120 = "application-icon-120"; + public static final String APPLICATION_ICON_160 = "application-icon-160"; + public static final String APPLICATION_ICON_240 = "application-icon-240"; + public static final String APPLICATION_ICON_320 = "application-icon-320"; + + // 所需设备属性 + private List features; + // 图标 + private String icon; + // 各分辨率下图标路径 + private Map icons; + // 应用程序名 + private String label; + // 入口Activity + private String launchableActivity; + // 支持的Android平台最低版本号 + private String minSdkVersion; + // 主包名 + private String packageName; + // 支持的SDK版本 + private String sdkVersion; + // Apk文件大小(字节) + private long size; + // 目标SDK版本 + private String targetSdkVersion; + // 所需权限 + private List usesPermissions; + // 内部版本号 + private String versionCode; + // 外部版本号 + private String versionName; + + public ApkInfo() { + this.features = new ArrayList<>(); + this.icons = new HashMap<>(); + this.usesPermissions = new ArrayList<>(); + } + + public List getFeatures() { + return features; + } + + public void setFeatures(List features) { + this.features = features; + } + + public void addToFeatures(String feature) { + this.features.add(feature); + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public Map getIcons() { + return icons; + } + + public void setIcons(Map icons) { + this.icons = icons; + } + + public void addToIcons(String key, String value) { + this.icons.put(key, value); + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getLaunchableActivity() { + return launchableActivity; + } + + public void setLaunchableActivity(String launchableActivity) { + this.launchableActivity = launchableActivity; + } + + public String getMinSdkVersion() { + return minSdkVersion; + } + + public void setMinSdkVersion(String minSdkVersion) { + this.minSdkVersion = minSdkVersion; + } + + public String getPackageName() { + return packageName; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public String getSdkVersion() { + return sdkVersion; + } + + public void setSdkVersion(String sdkVersion) { + this.sdkVersion = sdkVersion; + } + + public long getSize() { + return size; + } + + public void setSize(long size) { + this.size = size; + } + + public String getTargetSdkVersion() { + return targetSdkVersion; + } + + public void setTargetSdkVersion(String targetSdkVersion) { + this.targetSdkVersion = targetSdkVersion; + } + + public List getUsesPermissions() { + return usesPermissions; + } + + public void setUsesPermissions(List usesPermissions) { + this.usesPermissions = usesPermissions; + } + + public void addToUsesPermissions(String usesPermission) { + this.usesPermissions.add(usesPermission); + } + + public String getVersionCode() { + return versionCode; + } + + public void setVersionCode(String versionCode) { + this.versionCode = versionCode; + } + + public String getVersionName() { + return versionName; + } + + public void setVersionName(String versionName) { + this.versionName = versionName; + } + + @Override + public String toString() { + return "ApkInfo [features=" + features + ", icon=" + icon + ", icons=" + icons + ", label=" + label + ", launchableActivity=" + launchableActivity + ", minSdkVersion=" + minSdkVersion + ", packageName=" + packageName + ", sdkVersion=" + sdkVersion + ", size=" + size + ", targetSdkVersion=" + targetSdkVersion + ", usesPermissions=" + usesPermissions + ", versionCode=" + versionCode + ", versionName=" + versionName + "]"; + } + +} \ No newline at end of file diff --git a/src/main/java/net/geedge/asw/module/app/util/ApkUtil.java b/src/main/java/net/geedge/asw/module/app/util/ApkUtil.java new file mode 100644 index 0000000..1d34e79 --- /dev/null +++ b/src/main/java/net/geedge/asw/module/app/util/ApkUtil.java @@ -0,0 +1,110 @@ +package net.geedge.asw.module.app.util; + +import cn.hutool.log.Log; +import net.geedge.asw.common.util.T; + +import java.io.*; + +public class ApkUtil { + + private static final Log log = Log.get(); + + public static final String APPLICATION = "application:"; + public static final String APPLICATION_ICON = "application-icon"; + public static final String APPLICATION_LABEL = "application-label"; + public static final String APPLICATION_LABEL_N = "application: label"; + public static final String DENSITIES = "densities"; + public static final String LAUNCHABLE_ACTIVITY = "launchable"; + public static final String PACKAGE = "package"; + public static final String SDK_VERSION = "sdkVersion"; + public static final String SUPPORTS_ANY_DENSITY = "support-any-density"; + public static final String SUPPORTS_SCREENS = "support-screens"; + public static final String TARGET_SDK_VERSION = "targetSdkVersion"; + public static final String VERSION_CODE = "versionCode"; + public static final String VERSION_NAME = "versionName"; + public static final String USES_FEATURE = "uses-feature"; + public static final String USES_IMPLIED_FEATURE = "uses-implied-feature"; + public static final String USES_PERMISSION = "uses-permission"; + + private static final String SPLIT_REGEX = "(: )|(=')|(' )|'"; + + private ProcessBuilder builder; + // aapt 所在目录 + private String aaptToolPath = "aapt"; + + public ApkUtil() { + builder = new ProcessBuilder(); + builder.redirectErrorStream(true); + } + + public String getAaptToolPath() { + return aaptToolPath; + } + + public void setAaptToolPath(String aaptToolPath) { + this.aaptToolPath = aaptToolPath; + } + + public ApkInfo parseApk(String apkPath) { + String aaptTool = aaptToolPath; + Process process = null; + InputStream inputStream = null; + BufferedReader bufferedReader = null; + try { + process = builder.command(aaptTool, "d", "badging", apkPath).start(); + inputStream = process.getInputStream(); + bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8")); + ApkInfo apkInfo = new ApkInfo(); + apkInfo.setSize(new File(apkPath).length()); + String temp = null; + while ((temp = bufferedReader.readLine()) != null) { + setApkInfoProperty(apkInfo, temp); + } + return apkInfo; + } catch (IOException e) { + log.error(e, "[parseApk] [error] [path: {}]", apkPath); + return null; + } finally { + if (process != null) { + process.destroy(); + } + T.IoUtil.close(inputStream); + T.IoUtil.close(bufferedReader); + } + } + + private void setApkInfoProperty(ApkInfo apkInfo, String source) { + if (source.startsWith(APPLICATION)) { + String[] rs = source.split("( icon=')|'"); + apkInfo.setIcon(rs[rs.length - 1]); + } else if (source.startsWith(APPLICATION_ICON)) { + apkInfo.addToIcons(getKeyBeforeColon(source), getPropertyInQuote(source)); + } else if (source.startsWith(APPLICATION_LABEL)) { + apkInfo.setLabel(getPropertyInQuote(source)); + } else if (source.startsWith(LAUNCHABLE_ACTIVITY)) { + apkInfo.setLaunchableActivity(getPropertyInQuote(source)); + } else if (source.startsWith(PACKAGE)) { + String[] packageInfo = source.split(SPLIT_REGEX); + apkInfo.setPackageName(packageInfo[2]); + apkInfo.setVersionCode(packageInfo[4]); + apkInfo.setVersionName(packageInfo[6]); + } else if (source.startsWith(SDK_VERSION)) { + apkInfo.setSdkVersion(getPropertyInQuote(source)); + } else if (source.startsWith(TARGET_SDK_VERSION)) { + apkInfo.setTargetSdkVersion(getPropertyInQuote(source)); + } else if (source.startsWith(USES_PERMISSION)) { + apkInfo.addToUsesPermissions(getPropertyInQuote(source)); + } else if (source.startsWith(USES_FEATURE)) { + apkInfo.addToFeatures(getPropertyInQuote(source)); + } + } + + private String getKeyBeforeColon(String source) { + return source.substring(0, source.indexOf(':')); + } + + private String getPropertyInQuote(String source) { + int index = source.indexOf("'") + 1; + return source.substring(index, source.indexOf('\'', index)); + } +} \ No newline at end of file diff --git a/src/main/java/net/geedge/asw/module/app/util/PkgConstant.java b/src/main/java/net/geedge/asw/module/app/util/PkgConstant.java new file mode 100644 index 0000000..be61762 --- /dev/null +++ b/src/main/java/net/geedge/asw/module/app/util/PkgConstant.java @@ -0,0 +1,37 @@ +package net.geedge.asw.module.app.util; + +import net.geedge.asw.common.util.T; + +import java.io.File; + +public class PkgConstant { + + /** + * android packages file dir + */ + public static File APK_FILES_DIR = T.FileUtil.file(T.WebPathUtil.getRootPath(), "apk_files"); + + /** + * support platform + */ + public enum Platform { + ANDROID("android"), + + IOS("ios"), + + WINDOWS("windows"), + + LINUX("linux"); + + private String value; + + Platform(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + } + +} diff --git a/src/main/resources/db/mapper/app/PackageMapper.xml b/src/main/resources/db/mapper/app/PackageMapper.xml index 9d1287e..2bc64e0 100644 --- a/src/main/resources/db/mapper/app/PackageMapper.xml +++ b/src/main/resources/db/mapper/app/PackageMapper.xml @@ -3,12 +3,51 @@ + + + + + + + + + + + + + + + - SELECT - pkg.* + pkg.*, + + cu.id AS cu_id, + cu.name AS cu_name, + cu.user_name AS cu_user_name, + + uu.id AS uu_id, + uu.name AS uu_name, + uu.user_name AS uu_user_name FROM package pkg + LEFT JOIN sys_user cu ON pkg.create_user_id = cu.id + LEFT JOIN sys_user uu ON pkg.update_user_id = uu.id LEFT JOIN workbook_resource wr ON pkg.id = wr.resource_id AND wr.resource_type = 'package' diff --git a/src/main/resources/db/mapper/runner/PcapMapper.xml b/src/main/resources/db/mapper/runner/PcapMapper.xml index 61f8c0b..433720f 100644 --- a/src/main/resources/db/mapper/runner/PcapMapper.xml +++ b/src/main/resources/db/mapper/runner/PcapMapper.xml @@ -28,7 +28,6 @@ - @@ -54,7 +53,6 @@ pkg.id AS pkg_id, pkg.platform AS pkg_platform, pkg.version AS pkg_version, - pkg.logo AS pkg_logo, pkg.identifier AS pkg_identifier, run.id AS run_id, diff --git a/src/main/resources/db/migration/V1.0.01__INIT_TABLES.sql b/src/main/resources/db/migration/V1.0.01__INIT_TABLES.sql index 7ab3bb8..257e7cf 100644 --- a/src/main/resources/db/migration/V1.0.01__INIT_TABLES.sql +++ b/src/main/resources/db/migration/V1.0.01__INIT_TABLES.sql @@ -361,11 +361,13 @@ DROP TABLE IF EXISTS `package`; CREATE TABLE `package` ( `id` varchar(64) NOT NULL COMMENT '主键', `name` varchar(256) NOT NULL DEFAULT '' COMMENT '名称', - `logo` varchar(512) NOT NULL DEFAULT '' COMMENT '图标,图标文件 url 地址', + `icon` text NOT NULL DEFAULT '' COMMENT '图标,图标文件base64内容', `description` text NOT NULL DEFAULT '' COMMENT '描述信息', `platform` varchar(256) NOT NULL DEFAULT '' COMMENT '操作系统; 可选值:android,ios,windows,linux', `version` varchar(256) NOT NULL DEFAULT '' COMMENT '安装包版本', `identifier` varchar(256) NOT NULL DEFAULT '' COMMENT '唯一标识;android:package name,ios:bundle id', + `path` varchar(512) NOT NULL DEFAULT '' COMMENT '安装包文件路径', + `size` bigint(20) NOT NULL DEFAULT 0 COMMENT '文件大小', `create_timestamp` bigint(20) NOT NULL COMMENT '创建时间戳', `update_timestamp` bigint(20) NOT NULL COMMENT '更新时间戳', `create_user_id` varchar(64) NOT NULL COMMENT '创建人', diff --git a/src/main/resources/lib/aapt b/src/main/resources/lib/aapt new file mode 100644 index 0000000..ef14966 Binary files /dev/null and b/src/main/resources/lib/aapt differ