mirror of
https://github.com/OpenListTeam/OpenList-Desktop.git
synced 2025-11-25 03:14:56 +08:00
Compare commits
10 Commits
renovate/z
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9c2cc3deb | ||
|
|
5923aa4e6e | ||
|
|
9c9b3e713f | ||
|
|
0ff3fee308 | ||
|
|
0dae544d54 | ||
|
|
f3a5e2556f | ||
|
|
a3a6ef03a5 | ||
|
|
e4ab2184eb | ||
|
|
4c76f31885 | ||
|
|
68411aaaf3 |
230
.github/scripts/Connect-SimplySign-Enhanced.ps1
vendored
Normal file
230
.github/scripts/Connect-SimplySign-Enhanced.ps1
vendored
Normal 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"
|
||||
252
.github/scripts/configure-simplysign-registry.ps1
vendored
Normal file
252
.github/scripts/configure-simplysign-registry.ps1
vendored
Normal 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
112
.github/scripts/install-simplysign.sh
vendored
Normal 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!"
|
||||
82
.github/workflows/build-test.yml
vendored
82
.github/workflows/build-test.yml
vendored
@@ -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
|
||||
|
||||
55
.github/workflows/release.yml
vendored
55
.github/workflows/release.yml
vendored
@@ -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 }}'
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
2
src-tauri/Cargo.lock
generated
2
src-tauri/Cargo.lock
generated
@@ -2940,7 +2940,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openlist-desktop"
|
||||
version = "0.6.1"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.22.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "openlist-desktop"
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
description = "A Tauri App"
|
||||
authors = ["Kuingsmile"]
|
||||
edition = "2024"
|
||||
|
||||
@@ -1,4 +1,23 @@
|
||||
#!/bin/bash
|
||||
chmod +x /usr/bin/install-openlist-service
|
||||
chmod +x /usr/bin/uninstall-openlist-service
|
||||
chmod +x /usr/bin/openlist-desktop-service
|
||||
|
||||
# Migration: Clean up old installation in /usr/bin if it exists
|
||||
# This handles upgrades from previous versions that installed to /usr/bin
|
||||
if [ -f "/usr/bin/openlist-desktop" ] && [ ! -L "/usr/bin/openlist-desktop" ]; then
|
||||
echo "Migrating from old installation location (/usr/bin) to /opt/OpenList-Desktop"
|
||||
# Remove old binaries that are now in /opt
|
||||
rm -f /usr/bin/install-openlist-service
|
||||
rm -f /usr/bin/uninstall-openlist-service
|
||||
rm -f /usr/bin/openlist-desktop-service
|
||||
rm -f /usr/bin/openlist
|
||||
rm -f /usr/bin/rclone
|
||||
# Note: /usr/bin/openlist-desktop will be replaced with symlink below
|
||||
fi
|
||||
|
||||
# Set execute permissions for binaries in /opt
|
||||
chmod +x /opt/OpenList-Desktop/install-openlist-service
|
||||
chmod +x /opt/OpenList-Desktop/uninstall-openlist-service
|
||||
chmod +x /opt/OpenList-Desktop/openlist-desktop-service
|
||||
|
||||
# Create symlink for easy command-line access
|
||||
# Using -f flag to force creation even if file exists
|
||||
ln -sf /opt/OpenList-Desktop/openlist-desktop /usr/bin/openlist-desktop
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
#!/bin/bash
|
||||
/usr/bin/uninstall-openlist-service
|
||||
/opt/OpenList-Desktop/uninstall-openlist-service
|
||||
|
||||
# Remove symlink
|
||||
rm -f /usr/bin/openlist-desktop
|
||||
|
||||
@@ -114,7 +114,7 @@ async fn is_rclone_running() -> bool {
|
||||
let mut system = System::new_all();
|
||||
system.refresh_processes(sysinfo::ProcessesToUpdate::All, true);
|
||||
|
||||
for (_pid, process) in system.processes() {
|
||||
for process in system.processes().values() {
|
||||
let process_name = process.name().to_string_lossy().to_lowercase();
|
||||
|
||||
if process_name.contains("rclone") {
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}"))?
|
||||
@@ -17,43 +42,57 @@ fn get_app_dir() -> Result<PathBuf, String> {
|
||||
}
|
||||
|
||||
fn get_user_data_dir() -> Result<PathBuf, String> {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
let home = env::var("HOME").map_err(|_| "Failed to get HOME environment variable")?;
|
||||
let data_dir = PathBuf::from(home)
|
||||
.join("Library")
|
||||
.join("Application Support")
|
||||
.join("OpenList Desktop");
|
||||
fs::create_dir_all(&data_dir)
|
||||
.map_err(|e| format!("Failed to create data directory: {e}"))?;
|
||||
Ok(data_dir)
|
||||
}
|
||||
let data_dir = {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
let home = env::var("HOME").map_err(|_| "Failed to get HOME environment variable")?;
|
||||
PathBuf::from(home)
|
||||
.join("Library")
|
||||
.join("Application Support")
|
||||
.join("OpenList Desktop")
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
get_app_dir()
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let home = env::var("HOME").map_err(|_| "Failed to get HOME environment variable")?;
|
||||
PathBuf::from(home)
|
||||
.join(".local")
|
||||
.join("share")
|
||||
.join("OpenList Desktop")
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
let appdata =
|
||||
env::var("APPDATA").map_err(|_| "Failed to get APPDATA environment variable")?;
|
||||
PathBuf::from(appdata).join("OpenList Desktop")
|
||||
}
|
||||
};
|
||||
|
||||
fs::create_dir_all(&data_dir).map_err(|e| format!("Failed to create data directory: {e}"))?;
|
||||
|
||||
normalize_path(&data_dir)
|
||||
}
|
||||
|
||||
fn get_user_logs_dir() -> Result<PathBuf, String> {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
let home = env::var("HOME").map_err(|_| "Failed to get HOME environment variable")?;
|
||||
let logs_dir = PathBuf::from(home)
|
||||
.join("Library")
|
||||
.join("Logs")
|
||||
.join("OpenList Desktop");
|
||||
fs::create_dir_all(&logs_dir)
|
||||
.map_err(|e| format!("Failed to create logs directory: {e}"))?;
|
||||
Ok(logs_dir)
|
||||
}
|
||||
let logs_dir = {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
let home = env::var("HOME").map_err(|_| "Failed to get HOME environment variable")?;
|
||||
PathBuf::from(home)
|
||||
.join("Library")
|
||||
.join("Logs")
|
||||
.join("OpenList Desktop")
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
let logs = get_app_dir()?.join("logs");
|
||||
fs::create_dir_all(&logs).map_err(|e| e.to_string())?;
|
||||
Ok(logs)
|
||||
}
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
get_user_data_dir()?.join("logs")
|
||||
}
|
||||
};
|
||||
|
||||
fs::create_dir_all(&logs_dir).map_err(|e| format!("Failed to create logs directory: {e}"))?;
|
||||
normalize_path(&logs_dir)
|
||||
}
|
||||
|
||||
fn get_binary_path(binary: &str, service_name: &str) -> Result<PathBuf, String> {
|
||||
@@ -96,15 +135,7 @@ pub fn get_rclone_config_path() -> Result<PathBuf, String> {
|
||||
}
|
||||
|
||||
pub fn get_default_openlist_data_dir() -> Result<PathBuf, String> {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
Ok(get_user_data_dir()?.join("data"))
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
Ok(get_app_dir()?.join("data"))
|
||||
}
|
||||
Ok(get_user_data_dir()?.join("data"))
|
||||
}
|
||||
|
||||
pub fn get_service_log_path() -> Result<PathBuf, String> {
|
||||
@@ -113,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_app_dir()?.join("openlist-desktop-service.log"))
|
||||
Ok(get_app_logs_dir()?.join("openlist-desktop-service.log"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -11,7 +11,15 @@
|
||||
"conflicts": ["openlist-desktop"],
|
||||
"replaces": ["openlist-desktop"],
|
||||
"postInstallScript": "./packages/linux/post-install.sh",
|
||||
"preRemoveScript": "./packages/linux/pre-remove.sh"
|
||||
"preRemoveScript": "./packages/linux/pre-remove.sh",
|
||||
"files": {
|
||||
"/opt/OpenList-Desktop/openlist-desktop": "usr/bin/openlist-desktop",
|
||||
"/opt/OpenList-Desktop/install-openlist-service": "usr/bin/install-openlist-service",
|
||||
"/opt/OpenList-Desktop/uninstall-openlist-service": "usr/bin/uninstall-openlist-service",
|
||||
"/opt/OpenList-Desktop/openlist-desktop-service": "usr/bin/openlist-desktop-service",
|
||||
"/opt/OpenList-Desktop/openlist": "usr/bin/openlist",
|
||||
"/opt/OpenList-Desktop/rclone": "usr/bin/rclone"
|
||||
}
|
||||
},
|
||||
"rpm": {
|
||||
"depends": ["openssl"],
|
||||
@@ -20,7 +28,15 @@
|
||||
"conflicts": ["openlist-desktop"],
|
||||
"obsoletes": ["openlist-desktop"],
|
||||
"postInstallScript": "./packages/linux/post-install.sh",
|
||||
"preRemoveScript": "./packages/linux/pre-remove.sh"
|
||||
"preRemoveScript": "./packages/linux/pre-remove.sh",
|
||||
"files": {
|
||||
"/opt/OpenList-Desktop/openlist-desktop": "usr/bin/openlist-desktop",
|
||||
"/opt/OpenList-Desktop/install-openlist-service": "usr/bin/install-openlist-service",
|
||||
"/opt/OpenList-Desktop/uninstall-openlist-service": "usr/bin/uninstall-openlist-service",
|
||||
"/opt/OpenList-Desktop/openlist-desktop-service": "usr/bin/openlist-desktop-service",
|
||||
"/opt/OpenList-Desktop/openlist": "usr/bin/openlist",
|
||||
"/opt/OpenList-Desktop/rclone": "usr/bin/rclone"
|
||||
}
|
||||
}
|
||||
},
|
||||
"externalBin": [
|
||||
|
||||
@@ -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
|
||||
|
||||
2
src/types/types.d.ts
vendored
2
src/types/types.d.ts
vendored
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user