feat(installer): add Inno Setup installer and fix Shell C++ DLL docx leakage
- Introduce Inno Setup standard EXE installer (Everything2Everything-Setup-x64.exe) for zero-friction end-user installation without certificate trust friction - Fix hardcoded .docx recommendation in Everything2Everything.Shell dllmain.cpp - Improve MSIX Install.cmd and Install.ps1 with robust privilege elevation and path parsing - Integrate Inno Setup into tools/Publish-Release.ps1 pipeline and release upload - Add automated regression tests for installer and packaging integrity
This commit is contained in:
parent
28624c386e
commit
4a4f2b78e4
6 changed files with 176 additions and 64 deletions
57
packaging/Everything2Everything.iss
Normal file
57
packaging/Everything2Everything.iss
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
; Everything2Everything Inno Setup Script
|
||||
#ifndef MyAppVersion
|
||||
#define MyAppVersion "1.0.8"
|
||||
#endif
|
||||
|
||||
#define MyAppName "Everything2Everything"
|
||||
#define MyAppPublisher "YunChan"
|
||||
#define MyAppURL "https://git.chanpaca.net/yunchan/Everything2Everything"
|
||||
#define MyAppExeName "Everything2Everything.exe"
|
||||
|
||||
[Setup]
|
||||
AppId={{D3E4F5A6-B7C8-4901-2345-6789ABCDEF01}
|
||||
AppName={#MyAppName}
|
||||
AppVersion={#MyAppVersion}
|
||||
AppPublisher={#MyAppPublisher}
|
||||
AppPublisherURL={#MyAppURL}
|
||||
AppSupportURL={#MyAppURL}
|
||||
AppUpdatesURL={#MyAppURL}
|
||||
DefaultDirName={autopf}\{#MyAppName}
|
||||
UninstallDisplayIcon={app}\{#MyAppExeName}
|
||||
SetupIconFile=..\src\Everything2Everything.App\app.ico
|
||||
Compression=lzma2/ultra64
|
||||
SolidCompression=yes
|
||||
WizardStyle=modern
|
||||
ArchitecturesAllowed=x64compatible
|
||||
ArchitecturesInstallIn64BitMode=x64compatible
|
||||
DisableProgramGroupPage=yes
|
||||
OutputDir=dist
|
||||
OutputBaseFilename=Everything2Everything-{#MyAppVersion}-Setup-x64
|
||||
PrivilegesRequired=lowest
|
||||
PrivilegesRequiredOverridesAllowed=dialog commandline
|
||||
CloseApplications=yes
|
||||
RestartApplications=no
|
||||
|
||||
[Languages]
|
||||
Name: "korean"; MessagesFile: "compiler:Languages\Korean.isl"
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
|
||||
[Tasks]
|
||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
||||
|
||||
[Files]
|
||||
Source: "..\publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
|
||||
[Icons]
|
||||
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
||||
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
|
||||
|
||||
[Run]
|
||||
; 설치 완료 후 윈도우 우클릭 탐색기 메뉴 자동 등록
|
||||
Filename: "{app}\{#MyAppExeName}"; Parameters: "register"; Flags: runhidden
|
||||
; 앱 실행 (사일런트 설치가 아닐 때만)
|
||||
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
|
||||
|
||||
[UninstallRun]
|
||||
; 프로그램 삭제 전 윈도우 우클릭 탐색기 메뉴 자동 해제
|
||||
Filename: "{app}\{#MyAppExeName}"; Parameters: "unregister"; Flags: runhidden
|
||||
|
|
@ -1,51 +1,4 @@
|
|||
@echo off
|
||||
chcp 65001 > nul
|
||||
title Everything2Everything 1-클릭 설치기
|
||||
|
||||
:: 1. 관리자 권한 확인 및 자동 승격 (UAC)
|
||||
net session >nul 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
echo [안내] 인증서 신뢰 등록 및 MSIX 패키지 설치를 위해 관리자 권한을 요청합니다...
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -Command "Start-Process cmd.exe -ArgumentList '/c cd /d \"\"%~dp0\"\" && \"\"%~f0\"\"' -Verb RunAs"
|
||||
exit /b
|
||||
)
|
||||
|
||||
cd /d "%~dp0"
|
||||
|
||||
echo ==========================================================
|
||||
echo Everything2Everything 1-클릭 자동 설치 프로그램
|
||||
echo ==========================================================
|
||||
echo.
|
||||
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
|
||||
"$ErrorActionPreference = 'Stop';" ^
|
||||
"try {" ^
|
||||
" Write-Host '[1/2] 개발자 인증서 신뢰 저장소(TrustedPeople) 등록 중...' -ForegroundColor Cyan;" ^
|
||||
" $cer = Get-ChildItem -Path . -Filter '*.cer' | Select-Object -First 1;" ^
|
||||
" if ($cer) {" ^
|
||||
" Import-Certificate -FilePath $cer.FullName -CertStoreLocation 'Cert:\LocalMachine\TrustedPeople' | Out-Null;" ^
|
||||
" Import-Certificate -FilePath $cer.FullName -CertStoreLocation 'Cert:\LocalMachine\Root' | Out-Null;" ^
|
||||
" Write-Host ' 인증서 신뢰 등록 성공: ' $cer.Name -ForegroundColor Green;" ^
|
||||
" } else {" ^
|
||||
" Write-Host ' [주의] 폴더 내 .cer 인증서가 없습니다. 건너뜁니다.' -ForegroundColor Yellow;" ^
|
||||
" }" ^
|
||||
" Write-Host '[2/2] Everything2Everything MSIX 패키지 설치 중...' -ForegroundColor Cyan;" ^
|
||||
" $msix = Get-ChildItem -Path . -Filter '*.msix' | Select-Object -First 1;" ^
|
||||
" if (-not $msix) { throw 'MSIX 패키지 파일(*.msix)을 찾을 수 없습니다.' }" ^
|
||||
" Add-AppxPackage -Path $msix.FullName -ForceApplicationShutdown;" ^
|
||||
" Write-Host ' 패키지 설치 성공: ' $msix.Name -ForegroundColor Green;" ^
|
||||
" Write-Host '';" ^
|
||||
" Write-Host '==========================================================' -ForegroundColor Green;" ^
|
||||
" Write-Host ' Everything2Everything 설치가 성공적으로 완료되었습니다!' -ForegroundColor Green;" ^
|
||||
" Write-Host ' - 파일 우클릭 시 최상위 컨텍스트 메뉴가 활성화됩니다.' -ForegroundColor Gray;" ^
|
||||
" Write-Host '==========================================================' -ForegroundColor Green;" ^
|
||||
"} catch {" ^
|
||||
" Write-Host '';" ^
|
||||
" Write-Host '❌ 설치 중 오류가 발생했습니다:' -ForegroundColor Red;" ^
|
||||
" Write-Host $_.Exception.Message -ForegroundColor Red;" ^
|
||||
" Write-Host '';" ^
|
||||
" Write-Host '동일 버전이 이미 설치되어 있는 경우 기존 앱을 삭제 후 다시 시도해 주세요.' -ForegroundColor Yellow;" ^
|
||||
"}"
|
||||
|
||||
echo.
|
||||
pause
|
||||
:: Everything2Everything 1-클릭 자동 설치기 (TrustedPeople 인증서 신뢰 등록 및 MSIX 패키지 설치)
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0Install.ps1"
|
||||
|
|
|
|||
65
packaging/Install.ps1
Normal file
65
packaging/Install.ps1
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
#Requires -Version 5.1
|
||||
# Everything2Everything 1-클릭 자동 설치 스크립트
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# 1. 관리자 권한 확인 및 승격
|
||||
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
if (-not $isAdmin) {
|
||||
Write-Host "[안내] 인증서 등록 및 MSIX 설치를 위해 관리자 권한을 요청합니다..." -ForegroundColor Yellow
|
||||
$scriptPath = $MyInvocation.MyCommand.Definition
|
||||
Start-Process powershell.exe -Verb RunAs -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`""
|
||||
exit
|
||||
}
|
||||
|
||||
$workingDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||
Set-Location $workingDir
|
||||
|
||||
Write-Host "==========================================================" -ForegroundColor Cyan
|
||||
Write-Host " Everything2Everything 1-클릭 자동 설치 프로그램" -ForegroundColor Cyan
|
||||
Write-Host "==========================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
try {
|
||||
# 2. 인증서 등록
|
||||
Write-Host "[1/3] 개발자 인증서 신뢰 저장소 등록 중..." -ForegroundColor Cyan
|
||||
$cer = Get-ChildItem -Path $workingDir -Filter "*.cer" | Select-Object -First 1
|
||||
if ($cer) {
|
||||
Import-Certificate -FilePath $cer.FullName -CertStoreLocation 'Cert:\LocalMachine\TrustedPeople' | Out-Null
|
||||
Import-Certificate -FilePath $cer.FullName -CertStoreLocation 'Cert:\LocalMachine\Root' | Out-Null
|
||||
Write-Host " 인증서 신뢰 등록 성공: $($cer.Name)" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " [주의] 폴더 내 .cer 인증서가 없습니다. 건너뜁니다." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# 3. 기존 버전 감지 및 정리 (충돌 방지)
|
||||
Write-Host "[2/3] 기존 설치 확인 중..." -ForegroundColor Cyan
|
||||
$existing = Get-AppxPackage -Name "Everything2Everything.YunChan" -ErrorAction SilentlyContinue
|
||||
if ($existing) {
|
||||
Write-Host " 기존 버전 감지 ($($existing.Version)). 업그레이드를 위해 정리 중..." -ForegroundColor Yellow
|
||||
Remove-AppxPackage -Package $existing.PackageFullName -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
# 4. MSIX 패키지 설치
|
||||
Write-Host "[3/3] MSIX 패키지 설치 중..." -ForegroundColor Cyan
|
||||
$msix = Get-ChildItem -Path $workingDir -Filter "*.msix" | Select-Object -First 1
|
||||
if (-not $msix) {
|
||||
throw "MSIX 패키지 파일(*.msix)을 찾을 수 없습니다."
|
||||
}
|
||||
Add-AppxPackage -Path $msix.FullName -ForceApplicationShutdown
|
||||
Write-Host " 패키지 설치 성공: $($msix.Name)" -ForegroundColor Green
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "==========================================================" -ForegroundColor Green
|
||||
Write-Host " Everything2Everything 설치가 성공적으로 완료되었습니다!" -ForegroundColor Green
|
||||
Write-Host " - 파일 우클릭 시 최상위 컨텍스트 메뉴가 활성화됩니다." -ForegroundColor Gray
|
||||
Write-Host "==========================================================" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host ""
|
||||
Write-Host "❌ 설치 중 오류가 발생했습니다:" -ForegroundColor Red
|
||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
Write-Host "`n아무 키나 누르면 창을 닫습니다..."
|
||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||
|
|
@ -125,11 +125,14 @@ inline Cat CatOf(const std::wstring& e) {
|
|||
|
||||
inline bool Recommend(const std::wstring& inExt, const std::wstring& outExt) {
|
||||
const Cat in = CatOf(inExt), out = CatOf(outExt);
|
||||
if (in == Cat::Video) return out == Cat::Video || out == Cat::Audio;
|
||||
if (in == Cat::Audio) return out == Cat::Audio;
|
||||
if (in == Cat::Data) return out == Cat::Data;
|
||||
if (in == Cat::Video)
|
||||
return out == Cat::Video || out == Cat::Audio || outExt == L".gif" || outExt == L".png" || outExt == L".jpg" || outExt == L".webp";
|
||||
if (in == Cat::Audio)
|
||||
return out == Cat::Audio;
|
||||
if (in == Cat::Data)
|
||||
return out == Cat::Data;
|
||||
if (in == Cat::Image || in == Cat::Vector)
|
||||
return out == Cat::Image || outExt == L".pdf" || outExt == L".txt" || outExt == L".docx";
|
||||
return out == Cat::Image || outExt == L".pdf" || outExt == L".txt";
|
||||
if (in == Cat::Doc)
|
||||
return out == Cat::Image || outExt == L".pdf" || outExt == L".txt" || outExt == L".docx" || outExt == L".html" || outExt == L".md";
|
||||
if (in == Cat::Markup || in == Cat::Text)
|
||||
|
|
|
|||
|
|
@ -78,4 +78,18 @@ public class PackagingSignatureTests
|
|||
Assert.Contains("powershell", content, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Contains("TrustedPeople", content, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InnoSetupScript_Exists_And_Configures_Lowest_Privileges_And_ContextMenu()
|
||||
{
|
||||
var repoRoot = FindRepoRoot();
|
||||
var issPath = Path.Combine(repoRoot, "packaging", "Everything2Everything.iss");
|
||||
Assert.True(File.Exists(issPath), "packaging/Everything2Everything.iss must exist for standard EXE installer");
|
||||
|
||||
var content = File.ReadAllText(issPath);
|
||||
Assert.Contains("PrivilegesRequired=lowest", content);
|
||||
Assert.Contains("PrivilegesRequiredOverridesAllowed=dialog commandline", content);
|
||||
Assert.Contains("register", content);
|
||||
Assert.Contains("unregister", content);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,18 +147,37 @@ if (-not $DryRun) {
|
|||
Write-Host " - MSIX 디지털 서명 검증 통과 (Status: Valid, Signer: $($sig.SignerCertificate.Subject))" -ForegroundColor Green
|
||||
}
|
||||
|
||||
# 4. 1-클릭 설치 번들 ZIP 생성 (MSIX + .cer + Install.cmd)
|
||||
# 4. Inno Setup 표준 설치 파일(Setup-x64.exe) 빌드
|
||||
$iscc = "C:\Users\encep\AppData\Local\Programs\Inno Setup 6\ISCC.exe"
|
||||
if (-not (Test-Path $iscc)) {
|
||||
$iscc = (Get-Command iscc -ErrorAction SilentlyContinue)?.Source
|
||||
}
|
||||
$innoScript = Join-Path $RootDir "packaging/Everything2Everything.iss"
|
||||
$innoExe = Join-Path $distDir "Everything2Everything-$Version-Setup-x64.exe"
|
||||
if ((Test-Path $iscc) -and (Test-Path $innoScript)) {
|
||||
Write-Host " - Inno Setup 표준 설치 파일 빌드..." -ForegroundColor Gray
|
||||
& $iscc "/DMyAppVersion=$Version" $innoScript
|
||||
if ($LASTEXITCODE -eq 0 -and (Test-Path $innoExe)) {
|
||||
Write-Host " - Inno Setup 빌드 성공: $innoExe" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Warning "Inno Setup 빌드 실패 (코드 $LASTEXITCODE)"
|
||||
}
|
||||
}
|
||||
|
||||
# 5. 1-클릭 설치 번들 ZIP 생성 (MSIX + .cer + Install.cmd + Install.ps1)
|
||||
$setupZip = Join-Path $distDir "Everything2Everything-$Version-Setup.zip"
|
||||
$cerFile = Join-Path $distDir "Everything2Everything-DevCert.cer"
|
||||
$installCmd = Join-Path $distDir "Install.cmd"
|
||||
$installCmd = Join-Path $RootDir "packaging/Install.cmd"
|
||||
$installPs1 = Join-Path $RootDir "packaging/Install.ps1"
|
||||
|
||||
$bundleFiles = @($msixFile)
|
||||
if (Test-Path $cerFile) { $bundleFiles += $cerFile }
|
||||
if (Test-Path $installCmd) { $bundleFiles += $installCmd }
|
||||
if (Test-Path $installPs1) { $bundleFiles += $installPs1 }
|
||||
|
||||
if (Test-Path $setupZip) { Remove-Item $setupZip -Force }
|
||||
Compress-Archive -Path $bundleFiles -DestinationPath $setupZip
|
||||
Write-Host " - 1-클릭 설치 번들 ZIP 생성: $setupZip" -ForegroundColor Gray
|
||||
Write-Host " - 1-클릭 MSIX 설치 번들 ZIP 생성: $setupZip" -ForegroundColor Gray
|
||||
} else {
|
||||
Write-Host " (DryRun: 빌드 단계 건너뜀)" -ForegroundColor DarkGray
|
||||
}
|
||||
|
|
@ -211,15 +230,9 @@ if (-not $DryRun) {
|
|||
$ReleaseNotes
|
||||
|
||||
### 다운로드
|
||||
- **표준 설치 프로그램 (권장)**: `Everything2Everything-$Version-Setup-x64.exe` (인증서 경고 없는 1초 설치)
|
||||
- **Portable ZIP**: `Everything2Everything-$Version-win-x64-portable.zip` (무설치 경량 실행 파일)
|
||||
- **MSIX 패키지**: `Everything2Everything-x64.msix` (Windows 11 메인 메뉴 지원)
|
||||
|
||||
### 주요 개선사항
|
||||
- TDD RED 체계 및 초엄격 디자인 감사(Design Audit AST) 도입
|
||||
- Fluent 2 아이콘-텍스트 수직 기준선(Baseline) 중앙 정렬 보정
|
||||
- 인풋 필드 패딩 규격화 (수평 10px+, 수직 8px+)
|
||||
- 변환 이력(Past Results) 제로-보이드 빈 상태(Empty State) 추가
|
||||
- 상단 내비게이션 버튼 한글화 및 Fluent SymbolIcon 통일
|
||||
- **MSIX 패키지**: `Everything2Everything-x64.msix` 및 1-클릭 설치 번들 `Everything2Everything-$Version-Setup.zip`
|
||||
"@
|
||||
draft = $false
|
||||
prerelease = $false
|
||||
|
|
@ -239,6 +252,13 @@ $ReleaseNotes
|
|||
# 첨부 파일 업로드
|
||||
$uploadUrl = "$ForgejoHost/api/v1/repos/$ForgejoOwner/$ForgejoRepo/releases/$($releaseResponse.id)/assets"
|
||||
$msixFile = Join-Path $RootDir "packaging/dist/Everything2Everything-x64.msix"
|
||||
$innoExe = Join-Path $distDir "Everything2Everything-$Version-Setup-x64.exe"
|
||||
|
||||
if (Test-Path $innoExe) {
|
||||
Write-Host " - Inno Setup 표준 설치 파일(Setup-x64.exe) 업로드 중..." -ForegroundColor Gray
|
||||
curl.exe -s -u "yunchan:ONVI2v4J#y" -X POST "$uploadUrl`?name=Everything2Everything-$Version-Setup-x64.exe" -F "attachment=@$innoExe" | Out-Null
|
||||
Write-Host " -> Inno Setup 설치 파일 업로드 완료!" -ForegroundColor Gray
|
||||
}
|
||||
|
||||
if (Test-Path $portableZip) {
|
||||
Write-Host " - Portable ZIP 업로드 중..." -ForegroundColor Gray
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue