6 Commits

Author SHA1 Message Date
renovate[bot]
64351e62cc Update dependency fs-extra to v11.3.2 2025-11-18 10:53:51 +00:00
Copilot
0dae544d54 fix(mount): mount button disabled incorrectly on macOS when directory exists (#109) (#110)
Fix macOS mount button disabled issue (#109) - correct mount status logic and add directory creation.
2025-11-13 21:29:26 +08:00
GitHub Action
f3a5e2556f chore: bump version to 0.8.0 [skip ci] 2025-11-08 04:29:05 +00:00
Suyunmeng
a3a6ef03a5 feat(ui): persist log filter preferences in settings file
This commit improves the log viewer by persisting user filter preferences
across page navigation and application restarts.

Changes:
- Add log_filter_level and log_filter_source fields to AppConfig
- Store filter preferences in settings.json instead of localStorage
- Ensure filter preferences survive app restarts and page switches
- Fix clippy warning: use &Path instead of &PathBuf in normalize_path

The filter level and source selections are now saved to the persistent
settings file, providing a more reliable storage mechanism for Tauri
applications.
2025-11-08 11:19:18 +08:00
Suyunmeng
e4ab2184eb fix(data): fix data directory errors and log display issues 2025-11-08 09:53:57 +08:00
Suyunjing
4c76f31885 chore(ci): update ci configurations 2025-10-30 15:48:58 +08:00
15 changed files with 1397 additions and 817 deletions

View File

@@ -0,0 +1,230 @@
# Connect-SimplySign-Enhanced.ps1
# Registry-Enhanced TOTP Authentication for SimplySign Desktop
# Uses registry pre-configuration + TOTP credential injection approach
param(
[string]$OtpUri = $env:CERTUM_OTP_URI,
[string]$UserId = $env:CERTUM_USERNAME,
[string]$ExePath = $env:CERTUM_EXE_PATH
)
# Validate required parameters
if (-not $OtpUri) {
Write-Host "ERROR: CERTUM_OTP_URI environment variable not provided"
exit 1
}
if (-not $UserId) {
Write-Host "ERROR: CERTUM_USERNAME environment variable not provided"
exit 1
}
if (-not $ExePath) {
$ExePath = "C:\Program Files\Certum\SimplySign Desktop\SimplySignDesktop.exe"
}
Write-Host "=== REGISTRY-ENHANCED TOTP AUTHENTICATION ==="
Write-Host "Using registry pre-configuration + credential injection"
Write-Host "OTP URI provided (length: $($OtpUri.Length))"
Write-Host "User ID: $UserId"
Write-Host "Executable: $ExePath"
Write-Host ""
# Verify SimplySign Desktop exists
if (-not (Test-Path $ExePath)) {
Write-Host "ERROR: SimplySign Desktop not found at: $ExePath"
exit 1
}
# Parse the otpauth:// URI
$uri = [Uri]$OtpUri
# Parse query parameters (compatible with both PowerShell 5.1 and 7+)
try {
$q = [System.Web.HttpUtility]::ParseQueryString($uri.Query)
} catch {
$q = @{}
foreach ($part in $uri.Query.TrimStart('?') -split '&') {
$kv = $part -split '=', 2
if ($kv.Count -eq 2) {
$q[$kv[0]] = [Uri]::UnescapeDataString($kv[1])
}
}
}
$Base32 = $q['secret']
$Digits = if ($q['digits']) { [int]$q['digits'] } else { 6 }
$Period = if ($q['period']) { [int]$q['period'] } else { 30 }
$Algorithm = if ($q['algorithm']) { $q['algorithm'].ToUpper() } else { 'SHA256' }
# Validate supported algorithms
$SupportedAlgorithms = @('SHA1', 'SHA256', 'SHA512')
if ($Algorithm -notin $SupportedAlgorithms) {
Write-Host "ERROR: Unsupported algorithm: $Algorithm. Supported: $($SupportedAlgorithms -join ', ')"
exit 1
}
# TOTP Generator (inline C# implementation)
Add-Type -Language CSharp @"
using System;
using System.Security.Cryptography;
public static class Totp
{
private const string B32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
private static byte[] Base32Decode(string s)
{
s = s.TrimEnd('=').ToUpperInvariant();
int byteCount = s.Length * 5 / 8;
byte[] bytes = new byte[byteCount];
int bitBuffer = 0, bitsLeft = 0, idx = 0;
foreach (char c in s)
{
int val = B32.IndexOf(c);
if (val < 0) throw new ArgumentException("Invalid Base32 char: " + c);
bitBuffer = (bitBuffer << 5) | val;
bitsLeft += 5;
if (bitsLeft >= 8)
{
bytes[idx++] = (byte)(bitBuffer >> (bitsLeft - 8));
bitsLeft -= 8;
}
}
return bytes;
}
private static HMAC GetHmacAlgorithm(string algorithm, byte[] key)
{
switch (algorithm.ToUpper())
{
case "SHA1":
return new HMACSHA1(key);
case "SHA256":
return new HMACSHA256(key);
case "SHA512":
return new HMACSHA512(key);
default:
throw new ArgumentException("Unsupported algorithm: " + algorithm);
}
}
public static string Now(string secret, int digits, int period, string algorithm = "SHA256")
{
byte[] key = Base32Decode(secret);
long counter = DateTimeOffset.UtcNow.ToUnixTimeSeconds() / period;
byte[] cnt = BitConverter.GetBytes(counter);
if (BitConverter.IsLittleEndian) Array.Reverse(cnt);
byte[] hash;
using (var hmac = GetHmacAlgorithm(algorithm, key))
{
hash = hmac.ComputeHash(cnt);
}
int offset = hash[hash.Length - 1] & 0x0F;
int binary =
((hash[offset] & 0x7F) << 24) |
((hash[offset + 1] & 0xFF) << 16) |
((hash[offset + 2] & 0xFF) << 8) |
(hash[offset + 3] & 0xFF);
int otp = binary % (int)Math.Pow(10, digits);
return otp.ToString(new string('0', digits));
}
}
"@
function Get-TotpCode {
param([string]$Secret, [int]$Digits = 6, [int]$Period = 30, [string]$Algorithm = 'SHA256')
[Totp]::Now($Secret, $Digits, $Period, $Algorithm)
}
# Generate current TOTP code
$otp = Get-TotpCode -Secret $Base32 -Digits $Digits -Period $Period -Algorithm $Algorithm
Write-Host "Generated TOTP: $otp (using $Algorithm algorithm)"
Write-Host ""
# Launch SimplySign Desktop (registry should auto-open login dialog)
Write-Host "Launching SimplySign Desktop..."
Write-Host "Registry pre-configuration should auto-open login dialog"
$proc = Start-Process -FilePath $ExePath -PassThru
Write-Host "Process started with ID: $($proc.Id)"
Write-Host ""
# Wait for the application to initialize
Write-Host "Waiting for SimplySign Desktop to initialize..."
Start-Sleep -Seconds 3
# Create WScript.Shell for window interaction
$wshell = New-Object -ComObject WScript.Shell
# Try to focus the SimplySign Desktop window
Write-Host "Attempting to focus SimplySign Desktop window..."
$focused = $false
# Method 1: Focus by process ID (most reliable)
$focused = $wshell.AppActivate($proc.Id)
# Method 2: Focus by window title (fallback)
if (-not $focused) {
$focused = $wshell.AppActivate('SimplySign Desktop')
}
# Method 3: Multiple attempts with slight delays
for ($i = 0; (-not $focused) -and ($i -lt 10); $i++) {
Start-Sleep -Milliseconds 500
$focused = $wshell.AppActivate($proc.Id) -or $wshell.AppActivate('SimplySign Desktop')
Write-Host "Focus attempt $($i + 1): $focused"
}
if (-not $focused) {
Write-Host "ERROR: Could not bring SimplySign Desktop to foreground"
Write-Host "Login dialog may not be visible for credential injection"
exit 1
}
Write-Host "Successfully focused SimplySign Desktop window"
Write-Host ""
# Small delay to ensure window is ready for input
Start-Sleep -Milliseconds 400
# Inject credentials: Username + TAB + TOTP + ENTER
Write-Host "Injecting credentials into login dialog..."
Write-Host "Sending: Username -> TAB -> TOTP -> ENTER"
# Send the credential sequence
$wshell.SendKeys($UserId)
Start-Sleep -Milliseconds 200
$wshell.SendKeys("{TAB}")
Start-Sleep -Milliseconds 200
$wshell.SendKeys($otp)
Start-Sleep -Milliseconds 200
$wshell.SendKeys("{ENTER}")
Write-Host "Credentials injected successfully"
Write-Host ""
# Wait for authentication to process
Write-Host "Waiting for authentication to complete..."
Start-Sleep -Seconds 5
# Verify SimplySign Desktop is still running
$stillRunning = Get-Process -Id $proc.Id -ErrorAction SilentlyContinue
if ($stillRunning) {
Write-Host "SUCCESS: SimplySign Desktop is running"
Write-Host "Authentication should be complete"
Write-Host "Cloud certificate should now be available"
} else {
Write-Host "WARNING: SimplySign Desktop process has exited"
Write-Host "This may indicate authentication failure"
}
Write-Host ""
Write-Host "=== TOTP AUTHENTICATION COMPLETE ==="
Write-Host "Registry pre-configuration + credential injection finished"

View File

@@ -0,0 +1,252 @@
param(
[switch]$DebugMode = $false,
[switch]$VerifyOnly = $false
)
# SimplySign Desktop Registry Configuration Script
# Pre-configures optimal registry settings for automated login dialog display
Write-Host "=== SimplySign Desktop Registry Configuration ==="
if ($DebugMode) {
Write-Host "Debug mode enabled - verbose logging active"
}
# Registry path for SimplySign Desktop settings
$RegistryPath = "HKCU:\Software\Certum\SimplySign"
# Optimal configuration values for automation
$OptimalSettings = @{
"ShowLoginDialogOnStart" = 1
"ShowLoginDialogOnAppRequest" = 1
"RememberLastUserName" = 1
"Autostart" = 0
"UnregisterCertificatesOnDisconnect" = 0
"RememberPINinCSP" = 1
"ForgetPINinCSPonDisconnect" = 1
"LangID" = 9
}
# Function to check if registry path exists
function Test-RegistryPath {
param([string]$Path)
try {
$null = Get-Item -Path $Path -ErrorAction Stop
return $true
} catch {
return $false
}
}
# Function to get current registry value
function Get-RegistryValue {
param(
[string]$Path,
[string]$Name
)
try {
$value = Get-ItemProperty -Path $Path -Name $Name -ErrorAction Stop
return $value.$Name
} catch {
return $null
}
}
# Function to set registry value safely
function Set-RegistryValue {
param(
[string]$Path,
[string]$Name,
[int]$Value
)
try {
Set-ItemProperty -Path $Path -Name $Name -Value $Value -Type DWord -ErrorAction Stop
if ($DebugMode) {
Write-Host " Set $Name = $Value"
}
return $true
} catch {
Write-Host " ERROR: Failed to set $Name = $Value - $($_.Exception.Message)"
return $false
}
}
# Function to display current settings
function Show-CurrentSettings {
Write-Host "Current SimplySign Desktop registry settings:"
Write-Host "============================================="
if (-not (Test-RegistryPath $RegistryPath)) {
Write-Host "Registry path does not exist: $RegistryPath"
return
}
foreach ($setting in $OptimalSettings.Keys) {
$currentValue = Get-RegistryValue -Path $RegistryPath -Name $setting
if ($null -eq $currentValue) {
Write-Host " $setting : NOT SET"
} else {
Write-Host " $setting : $currentValue"
}
}
Write-Host ""
}
# Function to create registry structure
function Initialize-RegistryStructure {
Write-Host "Initializing registry structure..."
# Create parent keys if they don't exist
$ParentPaths = @(
"HKCU:\Software\Certum",
$RegistryPath
)
$allCreated = $true
foreach ($path in $ParentPaths) {
if (-not (Test-RegistryPath $path)) {
try {
New-Item -Path $path -Force -ErrorAction Stop | Out-Null
if ($DebugMode) {
Write-Host " Created registry path: $path"
}
} catch {
Write-Host " ERROR: Failed to create registry path: $path - $($_.Exception.Message)"
$allCreated = $false
}
} else {
if ($DebugMode) {
Write-Host " Registry path exists: $path"
}
}
}
return $allCreated
}
# Function to apply optimal configuration
function Set-OptimalConfiguration {
Write-Host "Applying optimal configuration for automation..."
$successCount = 0
$totalSettings = $OptimalSettings.Count
foreach ($setting in $OptimalSettings.Keys) {
$value = $OptimalSettings[$setting]
if (Set-RegistryValue -Path $RegistryPath -Name $setting -Value $value) {
$successCount++
}
}
Write-Host "Applied $successCount of $totalSettings settings successfully"
return ($successCount -eq $totalSettings)
}
# Function to verify configuration
function Test-Configuration {
Write-Host "Verifying configuration..."
$verificationResults = @{}
$allCorrect = $true
foreach ($setting in $OptimalSettings.Keys) {
$expectedValue = $OptimalSettings[$setting]
$actualValue = Get-RegistryValue -Path $RegistryPath -Name $setting
$isCorrect = ($actualValue -eq $expectedValue)
$verificationResults[$setting] = @{
Expected = $expectedValue
Actual = $actualValue
Correct = $isCorrect
}
if (-not $isCorrect) {
$allCorrect = $false
}
if ($DebugMode -or -not $isCorrect) {
$status = if ($isCorrect) { "OK" } else { "MISMATCH" }
Write-Host " $setting : Expected=$expectedValue, Actual=$actualValue [$status]"
}
}
return $verificationResults, $allCorrect
}
# Main execution
try {
Write-Host "Starting registry configuration process..."
Write-Host ""
# Show current state
Write-Host "BEFORE CONFIGURATION:"
Show-CurrentSettings
if ($VerifyOnly) {
Write-Host "Verification-only mode - no changes will be made"
$verificationResults, $allCorrect = Test-Configuration
if ($allCorrect) {
Write-Host "SUCCESS: All settings are correctly configured"
exit 0
} else {
Write-Host "CONFIGURATION NEEDED: Some settings require adjustment"
exit 1
}
}
# Initialize registry structure
if (-not (Initialize-RegistryStructure)) {
Write-Host "FATAL ERROR: Failed to initialize registry structure"
exit 1
}
# Apply optimal configuration
if (-not (Set-OptimalConfiguration)) {
Write-Host "ERROR: Failed to apply complete configuration"
exit 1
}
Write-Host ""
Write-Host "AFTER CONFIGURATION:"
Show-CurrentSettings
# Verify the configuration was applied correctly
$verificationResults, $allCorrect = Test-Configuration
if ($allCorrect) {
Write-Host "SUCCESS: Registry configuration completed successfully"
Write-Host ""
Write-Host "Key automation settings enabled:"
Write-Host " ShowLoginDialogOnStart = 1 (Login dialog will appear automatically)"
Write-Host " ShowLoginDialogOnAppRequest = 1 (Dialog appears when apps request access)"
Write-Host " RememberLastUserName = 1 (Username persistence for efficiency)"
Write-Host ""
Write-Host "Next steps:"
Write-Host "1. Launch SimplySign Desktop"
Write-Host "2. Login dialog should appear automatically"
Write-Host "3. Complete authentication process"
# Create a status file for the workflow to check
"REGISTRY_CONFIGURATION_SUCCESS" | Out-File -FilePath "registry_config_status.log" -Encoding UTF8
exit 0
} else {
Write-Host "ERROR: Configuration verification failed"
Write-Host "Some settings were not applied correctly"
"REGISTRY_CONFIGURATION_PARTIAL" | Out-File -FilePath "registry_config_status.log" -Encoding UTF8
exit 1
}
} catch {
Write-Host "FATAL ERROR: Registry configuration failed - $($_.Exception.Message)"
"REGISTRY_CONFIGURATION_FAILED" | Out-File -FilePath "registry_config_status.log" -Encoding UTF8
exit 1
}

112
.github/scripts/install-simplysign.sh vendored Normal file
View File

@@ -0,0 +1,112 @@
#!/bin/bash
# Install SimplySign Desktop - Clean MSI Installation
set -euo pipefail
echo "=== INSTALLING SIMPLYSIGN DESKTOP ==="
echo "Using proven installation method from successful testing..."
# Download SimplySign Desktop MSI
CERTUM_INSTALLER="SimplySignDesktop.msi"
echo "Downloading SimplySign Desktop MSI..."
if curl -L "https://files.certum.eu/software/SimplySignDesktop/Windows/9.3.2.67/SimplySignDesktop-9.3.2.67-64-bit-en.msi" -o "$CERTUM_INSTALLER" --fail --max-time 60; then
echo "✅ Downloaded SimplySign Desktop MSI ($(ls -lh "$CERTUM_INSTALLER" | awk '{print $5}'))"
else
echo "❌ Failed to download SimplySign Desktop"
exit 1
fi
# Install with proven method (matching successful test)
echo "Installing SimplySign Desktop..."
echo "Full command: msiexec /i \"$CERTUM_INSTALLER\" /quiet /norestart /l*v install.log ALLUSERS=1 REBOOT=ReallySuppress"
# Check for administrative privileges (like the successful test)
ADMIN_RIGHTS=false
if powershell -Command "([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)" 2>/dev/null; then
echo "✅ Running with administrative privileges"
ADMIN_RIGHTS=true
else
echo "⚠️ No explicit administrative privileges detected"
fi
# Use the exact method that worked: PowerShell with admin privileges
if [ "$ADMIN_RIGHTS" = true ]; then
echo "Running MSI installation with administrator privileges..."
powershell -Command "Start-Process -FilePath 'msiexec.exe' -ArgumentList '/i', '\"$CERTUM_INSTALLER\"', '/quiet', '/norestart', '/l*v', 'install.log', 'ALLUSERS=1', 'REBOOT=ReallySuppress' -Wait -NoNewWindow -PassThru" &
INSTALL_PID=$!
else
echo "Running MSI installation without explicit admin elevation..."
timeout 300 msiexec /i "$CERTUM_INSTALLER" /quiet /norestart /l*v install.log ALLUSERS=1 REBOOT=ReallySuppress &
INSTALL_PID=$!
fi
# Monitor with the same logic as successful test
echo "Monitoring installation progress..."
INSTALL_START_TIME=$(date +%s)
sleep 10
# Check if msiexec process is actually running (like successful test)
if kill -0 $INSTALL_PID 2>/dev/null; then
echo "MSI installation process is running (PID: $INSTALL_PID)"
# Monitor for up to 3 minutes with status updates
for i in {1..18}; do
sleep 10
CURRENT_TIME=$(date +%s)
ELAPSED=$((CURRENT_TIME - INSTALL_START_TIME))
if kill -0 $INSTALL_PID 2>/dev/null; then
echo "Installation still running after ${ELAPSED} seconds..."
# Check log file growth
if [ -f "install.log" ]; then
LOG_SIZE=$(stat -c%s "install.log" 2>/dev/null || stat -f%z "install.log" 2>/dev/null || echo 0)
echo " Log file size: $LOG_SIZE bytes"
fi
else
echo "MSI installation completed after ${ELAPSED} seconds"
break
fi
done
# Final wait if still running
if kill -0 $INSTALL_PID 2>/dev/null; then
echo "Installation taking longer, waiting for completion..."
wait $INSTALL_PID 2>/dev/null || echo "Installation process ended"
fi
else
echo "MSI installation process ended quickly"
fi
# Quick success check using proven patterns
INSTALLATION_SUCCESSFUL=false
if [ -f "install.log" ]; then
if grep -qi "Installation.*operation.*completed.*successfully\|Installation.*success.*or.*error.*status.*0\|MainEngineThread.*is.*returning.*0\|Windows.*Installer.*installed.*the.*product" install.log 2>/dev/null; then
echo "✅ Installation successful (confirmed by log patterns)"
INSTALLATION_SUCCESSFUL=true
fi
fi
# Verify installation directory
INSTALL_PATH="/c/Program Files/Certum/SimplySign Desktop"
if [ -d "$INSTALL_PATH" ]; then
echo "✅ SimplySign Desktop installed successfully"
echo "✅ Virtual card emulation now active for code signing"
INSTALLATION_SUCCESSFUL=true
# Set output for GitHub Actions
if [ -n "${GITHUB_OUTPUT:-}" ]; then
echo "SIMPLYSIGN_PATH=$INSTALL_PATH" >> "$GITHUB_OUTPUT"
fi
fi
if [ "$INSTALLATION_SUCCESSFUL" = false ]; then
echo "❌ Installation verification failed"
echo "Last 10 lines of install log:"
tail -10 install.log 2>/dev/null || echo "No install log available"
exit 1
fi
echo "🎉 SimplySign Desktop installation completed successfully!"

View File

@@ -21,6 +21,10 @@ env:
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
# Certum cloud code signing for Windows
CERTUM_OTP_URI: ${{ secrets.CERTUM_OTP_URI }}
CERTUM_USERNAME: ${{ secrets.CERTUM_USERNAME }}
CERTUM_CERTIFICATE_SHA1: ${{ secrets.CERTUM_CERTIFICATE_SHA1 }}
concurrency:
group: "${{ github.workflow }} - ${{ github.head_ref || github.ref }}"
@@ -174,43 +178,64 @@ jobs:
p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }}
p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
- name: Import Windows certificate
if: matrix.os == 'windows-latest' && env.WINDOWS_CERTIFICATE != ''
env:
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
- name: Setup Certum Code Signing (Windows)
if: matrix.platform == 'windows'
run: |
if ($env:WINDOWS_CERTIFICATE) {
New-Item -ItemType directory -Path certificate
Set-Content -Path certificate/tempCert.txt -Value $env:WINDOWS_CERTIFICATE
certutil -decode certificate/tempCert.txt certificate/certificate.pfx
Remove-Item -path certificate -include tempCert.txt
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
}
echo "=== SETTING UP CERTUM CODE SIGNING FOR WINDOWS ==="
echo "Installing SimplySign Desktop and configuring for automatic authentication"
# Install SimplySign Desktop
chmod +x ./.github/scripts/install-simplysign.sh
./.github/scripts/install-simplysign.sh
# Configure registry for auto-login dialog
echo "Configuring registry for automatic login dialog..."
powershell -ExecutionPolicy Bypass -File "./.github/scripts/configure-simplysign-registry.ps1"
echo "Certum signing environment ready"
shell: bash
- name: Authenticate Certum (Windows)
if: matrix.platform == 'windows'
env:
CERTUM_OTP_URI: ${{ secrets.CERTUM_OTP_URI }}
CERTUM_USERNAME: ${{ secrets.CERTUM_USERNAME }}
run: |
echo "=== CERTUM AUTHENTICATION ==="
echo "Authenticating with Certum cloud certificate using TOTP"
# Authenticate with Certum using our enhanced script
powershell -ExecutionPolicy Bypass -File "./.github/scripts/Connect-SimplySign-Enhanced.ps1"
echo "Authentication completed"
shell: bash
- name: Configure Certum Certificate Thumbprint (Windows)
if: matrix.platform == 'windows'
shell: bash
run: |
echo "=== CONFIGURING CERTUM CERTIFICATE THUMBPRINT ==="
CONFIG_PATH="src-tauri/tauri.windows.conf.json"
THUMBPRINT="${{ secrets.CERTUM_CERTIFICATE_SHA1 }}"
# Update the certificateThumbprint field using jq
jq --arg thumbprint "$THUMBPRINT" '.bundle.windows.certificateThumbprint = $thumbprint' "$CONFIG_PATH" > tmp.$$ && mv tmp.$$ "$CONFIG_PATH"
echo "Certificate thumbprint configured: $THUMBPRINT"
- name: Build the app
if: matrix.platform == 'windows' || matrix.platform == 'linux'
run: |
yarn build --target ${{ matrix.target }}
uses: tauri-apps/tauri-action@v0
env:
NODE_OPTIONS: "--max_old_space_size=4096"
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
# macOS signing and notarization environment variables
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
with:
args: --target ${{ matrix.target }}
- name: Build the app (macOS)
uses: tauri-apps/tauri-action@v0
if: matrix.platform == 'macos'
run: |
export TAURI_SKIP_SIDECAR_SIGNATURE_CHECK=true
yarn build --target ${{ matrix.target }}
env:
NODE_OPTIONS: "--max_old_space_size=4096"
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
@@ -222,8 +247,9 @@ jobs:
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
TAURI_SKIP_SIDECAR_SIGNATURE_CHECK: "true"
with:
args: --target ${{ matrix.target }}
- name: Upload artifacts
uses: actions/upload-artifact@v4

View File

@@ -26,6 +26,10 @@ env:
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
# Certum cloud code signing for Windows
CERTUM_OTP_URI: ${{ secrets.CERTUM_OTP_URI }}
CERTUM_USERNAME: ${{ secrets.CERTUM_USERNAME }}
CERTUM_CERTIFICATE_SHA1: ${{ secrets.CERTUM_CERTIFICATE_SHA1 }}
PERSONAL_GITHUB_TOKEN: ${{ secrets.PERSONAL_GITHUB_TOKEN }}
concurrency:
group: "${{ github.workflow }} - ${{ github.head_ref || github.ref }}"
@@ -396,17 +400,50 @@ jobs:
p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }}
p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
- name: import windows certificate
- name: Setup Certum Code Signing (Windows)
if: matrix.os == 'windows-latest'
run: |
echo "=== SETTING UP CERTUM CODE SIGNING FOR WINDOWS ==="
echo "Installing SimplySign Desktop and configuring for automatic authentication"
# Install SimplySign Desktop
chmod +x ./.github/scripts/install-simplysign.sh
./.github/scripts/install-simplysign.sh
# Configure registry for auto-login dialog
echo "Configuring registry for automatic login dialog..."
powershell -ExecutionPolicy Bypass -File "./.github/scripts/configure-simplysign-registry.ps1"
echo "Certum signing environment ready"
shell: bash
- name: Authenticate Certum (Windows)
if: matrix.os == 'windows-latest'
env:
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
CERTUM_OTP_URI: ${{ secrets.CERTUM_OTP_URI }}
CERTUM_USERNAME: ${{ secrets.CERTUM_USERNAME }}
run: |
New-Item -ItemType directory -Path certificate
Set-Content -Path certificate/tempCert.txt -Value $env:WINDOWS_CERTIFICATE
certutil -decode certificate/tempCert.txt certificate/certificate.pfx
Remove-Item -path certificate -include tempCert.txt
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
echo "=== CERTUM AUTHENTICATION ==="
echo "Authenticating with Certum cloud certificate using TOTP"
# Authenticate with Certum using our enhanced script
powershell -ExecutionPolicy Bypass -File "./.github/scripts/Connect-SimplySign-Enhanced.ps1"
echo "Authentication completed"
shell: bash
- name: Configure Certum Certificate Thumbprint (Windows)
if: matrix.os == 'windows-latest'
shell: bash
run: |
echo "=== CONFIGURING CERTUM CERTIFICATE THUMBPRINT ==="
CONFIG_PATH="src-tauri/tauri.windows.conf.json"
THUMBPRINT="${{ secrets.CERTUM_CERTIFICATE_SHA1 }}"
# Update the certificateThumbprint field using jq
jq --arg thumbprint "$THUMBPRINT" '.bundle.windows.certificateThumbprint = $thumbprint' "$CONFIG_PATH" > tmp.$$ && mv tmp.$$ "$CONFIG_PATH"
echo "Certificate thumbprint configured: $THUMBPRINT"
- name: Build the app
uses: tauri-apps/tauri-action@v0
@@ -423,8 +460,6 @@ jobs:
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
# Enable signing and notarization for macOS
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
with:
tagName: ${{ needs.changelog.outputs.tag }}
releaseName: 'OpenList Desktop ${{ needs.changelog.outputs.tag }}'

View File

@@ -9,7 +9,7 @@
"tauri"
],
"private": true,
"version": "0.7.0",
"version": "0.8.0",
"author": {
"name": "OpenList Team",
"email": "96409857+Kuingsmile@users.noreply.github.com"
@@ -98,8 +98,11 @@
"tar": "^7.4.3",
"typescript": "^5.8.3",
"typescript-eslint": "^8.41.0",
"vite": "^7.1.3",
"vite": "^7.1.11",
"vue-eslint-parser": "^10.2.0",
"vue-tsc": "^3.0.6"
},
"overrides": {
"tmp": "^0.2.4"
}
}

View File

@@ -1,6 +1,6 @@
[package]
name = "openlist-desktop"
version = "0.7.0"
version = "0.8.0"
description = "A Tauri App"
authors = ["Kuingsmile"]
edition = "2024"

View File

@@ -204,6 +204,23 @@ pub async fn create_rclone_mount_remote_process(
let rclone_conf_path =
get_rclone_config_path().map_err(|e| format!("Failed to get rclone config path: {e}"))?;
// Extract mount point from args and create directory if it doesn't exist.
// The mount point is the second non-flag argument (first is remote:path).
let args_vec = split_args_vec(config.args.clone());
let mount_point_opt = args_vec.iter().filter(|arg| !arg.starts_with('-')).nth(1); // 0th is remote:path, 1st is mount_point
if let Some(mount_point) = mount_point_opt {
let mount_path = Path::new(mount_point);
if !mount_path.exists()
&& let Err(e) = fs::create_dir_all(mount_path)
{
return Err(format!(
"Failed to create mount point directory '{}': {}",
mount_point, e
));
}
}
let api_key = get_api_key();
let port = get_server_port();
let mut args: Vec<String> = vec![
@@ -211,7 +228,7 @@ pub async fn create_rclone_mount_remote_process(
"--config".into(),
rclone_conf_path.to_string_lossy().into_owned(),
];
args.extend(split_args_vec(config.args.clone()));
args.extend(args_vec);
let config = ProcessConfig {
id: config.id.clone(),
@@ -311,9 +328,10 @@ pub async fn get_mount_info_list(
Ok(is_mounted) => {
if process.is_running {
if is_mounted { "mounted" } else { "mounting" }
} else if is_mounted {
"unmounting"
} else {
// If process is not running, the mount point should be considered
// unmounted regardless of whether
// the directory exists or not
"unmounted"
}
}

View File

@@ -9,6 +9,8 @@ pub struct AppConfig {
pub open_links_in_browser: Option<bool>,
pub admin_password: Option<String>,
pub show_window_on_startup: Option<bool>,
pub log_filter_level: Option<String>,
pub log_filter_source: Option<String>,
}
impl AppConfig {
@@ -21,6 +23,8 @@ impl AppConfig {
open_links_in_browser: Some(false),
admin_password: None,
show_window_on_startup: Some(true),
log_filter_level: Some("all".to_string()),
log_filter_source: Some("openlist".to_string()),
}
}
}

View File

@@ -1,8 +1,33 @@
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::{env, fs};
pub static APP_ID: &str = "io.github.openlistteam.openlist.desktop";
// Normalize path without Windows long path prefix (\\?\)
// The \\?\ prefix breaks compatibility with some applications like SQLite
fn normalize_path(path: &Path) -> Result<PathBuf, String> {
#[cfg(target_os = "windows")]
{
// On Windows, use canonicalize but strip the \\?\ prefix if present
let canonical = path
.canonicalize()
.map_err(|e| format!("Failed to canonicalize path: {e}"))?;
let path_str = canonical.to_string_lossy();
if let Some(stripped) = path_str.strip_prefix(r"\\?\") {
Ok(PathBuf::from(stripped))
} else {
Ok(canonical)
}
}
#[cfg(not(target_os = "windows"))]
{
path.canonicalize()
.map_err(|e| format!("Failed to canonicalize path: {e}"))
}
}
fn get_app_dir() -> Result<PathBuf, String> {
let app_dir = env::current_exe()
.map_err(|e| format!("Failed to get current exe path: {e}"))?
@@ -46,9 +71,7 @@ fn get_user_data_dir() -> Result<PathBuf, String> {
fs::create_dir_all(&data_dir).map_err(|e| format!("Failed to create data directory: {e}"))?;
data_dir
.canonicalize()
.map_err(|e| format!("Failed to canonicalize data directory: {e}"))
normalize_path(&data_dir)
}
fn get_user_logs_dir() -> Result<PathBuf, String> {
@@ -69,9 +92,7 @@ fn get_user_logs_dir() -> Result<PathBuf, String> {
};
fs::create_dir_all(&logs_dir).map_err(|e| format!("Failed to create logs directory: {e}"))?;
logs_dir
.canonicalize()
.map_err(|e| format!("Failed to canonicalize logs directory: {e}"))
normalize_path(&logs_dir)
}
fn get_binary_path(binary: &str, service_name: &str) -> Result<PathBuf, String> {
@@ -123,16 +144,14 @@ pub fn get_service_log_path() -> Result<PathBuf, String> {
let home = env::var("HOME").map_err(|_| "Failed to get HOME environment variable")?;
let logs = PathBuf::from(home)
.join("Library")
.join("Application Support")
.join("io.github.openlistteam.openlist.service.bundle")
.join("Contents")
.join("MacOS")
.join("Logs")
.join("OpenList Desktop")
.join("openlist-desktop-service.log");
Ok(logs)
}
#[cfg(not(target_os = "macos"))]
{
Ok(get_user_data_dir()?.join("openlist-desktop-service.log"))
Ok(get_app_logs_dir()?.join("openlist-desktop-service.log"))
}
}

View File

@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "OpenList Desktop",
"version": "0.7.0",
"version": "0.8.0",
"identifier": "io.github.openlistteam.openlist.desktop",
"build": {
"beforeDevCommand": "yarn run dev",

View File

@@ -4,9 +4,9 @@
"bundle": {
"targets": ["nsis"],
"windows": {
"certificateThumbprint": "209114AD26E9B9B5788E4E9F6E522DFE8E4FABAD",
"certificateThumbprint": "",
"digestAlgorithm": "sha256",
"timestampUrl": "http://timestamp.comodoca.com",
"timestampUrl": "http://time.certum.pl",
"webviewInstallMode": {
"type": "embedBootstrapper",
"silent": true

View File

@@ -52,6 +52,8 @@ interface AppConfig {
open_links_in_browser?: boolean
admin_password?: string
show_window_on_startup?: boolean
log_filter_level?: string
log_filter_source?: string
}
interface MergedSettings {

View File

@@ -33,8 +33,8 @@ const logContainer = ref<HTMLElement>()
const searchInputRef = ref<HTMLInputElement>()
const autoScroll = ref(true)
const isPaused = ref(false)
const filterLevel = ref<string>('all')
const filterSource = ref<string>(localStorage.getItem('logFilterSource') || 'openlist')
const filterLevel = ref<string>(appStore.settings.app.log_filter_level || 'all')
const filterSource = ref<string>(appStore.settings.app.log_filter_source || 'openlist')
const searchQuery = ref('')
const selectedEntries = ref<Set<number>>(new Set())
const showFilters = ref(true)
@@ -55,8 +55,14 @@ const confirmDialogConfig = ref({
onCancel: () => {}
})
watch(filterLevel, async newValue => {
appStore.settings.app.log_filter_level = newValue
await appStore.saveSettings()
})
watch(filterSource, async newValue => {
localStorage.setItem('logFilterSource', newValue)
appStore.settings.app.log_filter_source = newValue
await appStore.saveSettings()
await appStore.loadLogs((newValue !== 'gin' ? newValue : 'openlist') as filterSourceType)
await scrollToBottom()
})

1383
yarn.lock

File diff suppressed because it is too large Load Diff