Merge branch 'v2.0' into task/refactor-spn
This commit is contained in:
@@ -4,13 +4,14 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/safing/portmaster/service/configure"
|
||||
"github.com/safing/portmaster/service/updates"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
scanConfig = updates.IndexScanConfig{
|
||||
Name: "Portmaster Binaries",
|
||||
Name: configure.DefaultBinaryIndexName,
|
||||
PrimaryArtifact: "linux_amd64/portmaster-core",
|
||||
BaseURL: "https://updates.safing.io/",
|
||||
IgnoreFiles: []string{
|
||||
|
||||
@@ -4,15 +4,12 @@ use std::sync::RwLock;
|
||||
use std::{collections::HashMap, sync::atomic::Ordering};
|
||||
|
||||
use log::{debug, error};
|
||||
use tauri::menu::{Menu, MenuItemKind};
|
||||
use tauri::tray::{MouseButton, MouseButtonState};
|
||||
use tauri::{
|
||||
image::Image,
|
||||
menu::{MenuBuilder, MenuItemBuilder, PredefinedMenuItem, SubmenuBuilder},
|
||||
tray::{TrayIcon, TrayIconBuilder},
|
||||
Wry,
|
||||
menu::{Menu, MenuBuilder, MenuItemBuilder, PredefinedMenuItem, SubmenuBuilder},
|
||||
tray::{MouseButton, MouseButtonState, TrayIcon, TrayIconBuilder},
|
||||
Manager, Wry,
|
||||
};
|
||||
use tauri::{Manager, Runtime};
|
||||
use tauri_plugin_window_state::{AppHandleExt, StateFlags};
|
||||
|
||||
use crate::config;
|
||||
@@ -33,6 +30,7 @@ use crate::{
|
||||
use tauri_plugin_dialog::{DialogExt, MessageDialogButtons};
|
||||
|
||||
pub type AppIcon = TrayIcon<Wry>;
|
||||
pub type ContextMenu = Menu<Wry>;
|
||||
|
||||
static SPN_STATE: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
@@ -46,12 +44,20 @@ enum IconColor {
|
||||
|
||||
static CURRENT_ICON_COLOR: RwLock<IconColor> = RwLock::new(IconColor::Red);
|
||||
pub static USER_THEME: RwLock<dark_light::Mode> = RwLock::new(dark_light::Mode::Default);
|
||||
|
||||
static SPN_STATUS_KEY: &str = "spn_status";
|
||||
static SPN_BUTTON_KEY: &str = "spn_toggle";
|
||||
static GLOBAL_STATUS_KEY: &str = "global_status";
|
||||
const OPEN_KEY: &str = "open";
|
||||
const EXIT_UI_KEY: &str = "exit_ui";
|
||||
const SPN_STATUS_KEY: &str = "spn_status";
|
||||
const SPN_BUTTON_KEY: &str = "spn_toggle";
|
||||
const GLOBAL_STATUS_KEY: &str = "global_status";
|
||||
const SHUTDOWN_KEY: &str = "shutdown";
|
||||
const SYSTEM_THEME_KEY: &str = "system_theme";
|
||||
const LIGHT_THEME_KEY: &str = "light_theme";
|
||||
const DARK_THEME_KEY: &str = "dark_theme";
|
||||
const RELOAD_KEY: &str = "reload";
|
||||
const FORCE_SHOW_KEY: &str = "force-show";
|
||||
|
||||
const PM_TRAY_ICON_ID: &str = "pm_icon";
|
||||
const PM_TRAY_MENU_ID: &str = "pm_tray_menu";
|
||||
|
||||
// Icons
|
||||
|
||||
@@ -115,51 +121,57 @@ fn get_icon(icon: IconColor) -> &'static [u8] {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_tray_menu(
|
||||
app: &mut tauri::App,
|
||||
) -> core::result::Result<AppIcon, Box<dyn std::error::Error>> {
|
||||
// Tray menu
|
||||
load_theme(app.handle());
|
||||
let open_btn = MenuItemBuilder::with_id("open", "Open App").build(app)?;
|
||||
let exit_ui_btn = MenuItemBuilder::with_id("exit_ui", "Exit UI").build(app)?;
|
||||
let shutdown_btn = MenuItemBuilder::with_id("shutdown", "Shut Down Portmaster").build(app)?;
|
||||
fn build_tray_menu(
|
||||
app: &tauri::AppHandle,
|
||||
status: &str,
|
||||
spn_status_text: &str,
|
||||
) -> core::result::Result<ContextMenu, Box<dyn std::error::Error>> {
|
||||
load_theme(app);
|
||||
|
||||
let global_status = MenuItemBuilder::with_id("global_status", "Status: Secured")
|
||||
let open_btn = MenuItemBuilder::with_id(OPEN_KEY, "Open App").build(app)?;
|
||||
let exit_ui_btn = MenuItemBuilder::with_id(EXIT_UI_KEY, "Exit UI").build(app)?;
|
||||
let shutdown_btn = MenuItemBuilder::with_id(SHUTDOWN_KEY, "Shut Down Portmaster").build(app)?;
|
||||
|
||||
let global_status = MenuItemBuilder::with_id(GLOBAL_STATUS_KEY, format!("Status: {}", status))
|
||||
.enabled(false)
|
||||
.build(app)
|
||||
.unwrap();
|
||||
|
||||
// Setup SPN status
|
||||
let spn_status = MenuItemBuilder::with_id(SPN_STATUS_KEY, "SPN: Disabled")
|
||||
let spn_status = MenuItemBuilder::with_id(SPN_STATUS_KEY, format!("SPN: {}", spn_status_text))
|
||||
.enabled(false)
|
||||
.build(app)
|
||||
.unwrap();
|
||||
|
||||
// Setup SPN button
|
||||
let spn_button = MenuItemBuilder::with_id(SPN_BUTTON_KEY, "Enable SPN")
|
||||
let spn_button_text = match spn_status_text {
|
||||
"disabled" => "Enable SPN",
|
||||
_ => "Disable SPN",
|
||||
};
|
||||
let spn_button = MenuItemBuilder::with_id(SPN_BUTTON_KEY, spn_button_text)
|
||||
.build(app)
|
||||
.unwrap();
|
||||
|
||||
let system_theme = MenuItemBuilder::with_id("system_theme", "System")
|
||||
let system_theme = MenuItemBuilder::with_id(SYSTEM_THEME_KEY, "System")
|
||||
.build(app)
|
||||
.unwrap();
|
||||
let light_theme = MenuItemBuilder::with_id("light_theme", "Light")
|
||||
let light_theme = MenuItemBuilder::with_id(LIGHT_THEME_KEY, "Light")
|
||||
.build(app)
|
||||
.unwrap();
|
||||
let dark_theme = MenuItemBuilder::with_id("dark_theme", "Dark")
|
||||
let dark_theme = MenuItemBuilder::with_id(DARK_THEME_KEY, "Dark")
|
||||
.build(app)
|
||||
.unwrap();
|
||||
let theme_menu = SubmenuBuilder::new(app, "Icon Theme")
|
||||
.items(&[&system_theme, &light_theme, &dark_theme])
|
||||
.build()?;
|
||||
|
||||
let force_show_window = MenuItemBuilder::with_id("force-show", "Force Show UI").build(app)?;
|
||||
let reload_btn = MenuItemBuilder::with_id("reload", "Reload User Interface").build(app)?;
|
||||
let force_show_window = MenuItemBuilder::with_id(FORCE_SHOW_KEY, "Force Show UI").build(app)?;
|
||||
let reload_btn = MenuItemBuilder::with_id(RELOAD_KEY, "Reload User Interface").build(app)?;
|
||||
let developer_menu = SubmenuBuilder::new(app, "Developer")
|
||||
.items(&[&reload_btn, &force_show_window])
|
||||
.build()?;
|
||||
|
||||
let menu = MenuBuilder::new(app)
|
||||
let menu = MenuBuilder::with_id(app, PM_TRAY_MENU_ID)
|
||||
.items(&[
|
||||
&open_btn,
|
||||
&PredefinedMenuItem::separator(app)?,
|
||||
@@ -176,11 +188,19 @@ pub fn setup_tray_menu(
|
||||
])
|
||||
.build()?;
|
||||
|
||||
return Ok(menu);
|
||||
}
|
||||
|
||||
pub fn setup_tray_menu(
|
||||
app: &mut tauri::App,
|
||||
) -> core::result::Result<AppIcon, Box<dyn std::error::Error>> {
|
||||
let menu = build_tray_menu(app.handle(), "Secured", "disabled")?;
|
||||
|
||||
let icon = TrayIconBuilder::with_id(PM_TRAY_ICON_ID)
|
||||
.icon(Image::from_bytes(get_red_icon()).unwrap())
|
||||
.menu(&menu)
|
||||
.on_menu_event(move |app, event| match event.id().as_ref() {
|
||||
"exit_ui" => {
|
||||
EXIT_UI_KEY => {
|
||||
let handle = app.clone();
|
||||
app.dialog()
|
||||
.message("This does not stop the Portmaster system service")
|
||||
@@ -196,15 +216,15 @@ pub fn setup_tray_menu(
|
||||
}
|
||||
});
|
||||
}
|
||||
"open" => {
|
||||
OPEN_KEY => {
|
||||
let _ = open_window(app);
|
||||
}
|
||||
"reload" => {
|
||||
RELOAD_KEY => {
|
||||
if let Ok(mut win) = open_window(app) {
|
||||
may_navigate_to_ui(&mut win, true);
|
||||
}
|
||||
}
|
||||
"force-show" => {
|
||||
FORCE_SHOW_KEY => {
|
||||
match create_main_window(app) {
|
||||
Ok(mut win) => {
|
||||
may_navigate_to_ui(&mut win, true);
|
||||
@@ -217,19 +237,19 @@ pub fn setup_tray_menu(
|
||||
}
|
||||
};
|
||||
}
|
||||
"spn_toggle" => {
|
||||
SPN_BUTTON_KEY => {
|
||||
if SPN_STATE.load(Ordering::Acquire) {
|
||||
app.portmaster().set_spn_enabled(false);
|
||||
} else {
|
||||
app.portmaster().set_spn_enabled(true);
|
||||
}
|
||||
}
|
||||
"shutdown" => {
|
||||
SHUTDOWN_KEY => {
|
||||
app.portmaster().trigger_shutdown();
|
||||
}
|
||||
"system_theme" => update_icon_theme(app, dark_light::Mode::Default),
|
||||
"dark_theme" => update_icon_theme(app, dark_light::Mode::Dark),
|
||||
"light_theme" => update_icon_theme(app, dark_light::Mode::Light),
|
||||
SYSTEM_THEME_KEY => update_icon_theme(app, dark_light::Mode::Default),
|
||||
DARK_THEME_KEY => update_icon_theme(app, dark_light::Mode::Dark),
|
||||
LIGHT_THEME_KEY => update_icon_theme(app, dark_light::Mode::Light),
|
||||
other => {
|
||||
error!("unknown menu event id: {}", other);
|
||||
}
|
||||
@@ -251,15 +271,11 @@ pub fn setup_tray_menu(
|
||||
}
|
||||
})
|
||||
.build(app)?;
|
||||
|
||||
Ok(icon)
|
||||
}
|
||||
|
||||
pub fn update_icon<R: Runtime>(
|
||||
icon: AppIcon,
|
||||
menu: Option<Menu<R>>,
|
||||
subsystems: HashMap<String, Subsystem>,
|
||||
spn_status: String,
|
||||
) {
|
||||
pub fn update_icon(icon: AppIcon, subsystems: HashMap<String, Subsystem>, spn_status: String) {
|
||||
// iterate over the subsystems and check if there's a module failure
|
||||
let failure = subsystems.values().map(|s| &s.module_status).fold(
|
||||
(subsystem::FAILURE_NONE, "".to_string()),
|
||||
@@ -273,14 +289,10 @@ pub fn update_icon<R: Runtime>(
|
||||
},
|
||||
);
|
||||
|
||||
if let Some(menu) = menu {
|
||||
if let Some(MenuItemKind::MenuItem(global_status)) = menu.get(GLOBAL_STATUS_KEY) {
|
||||
if failure.0 == subsystem::FAILURE_NONE {
|
||||
_ = global_status.set_text("Status: Secured");
|
||||
} else {
|
||||
_ = global_status.set_text(format!("Status: {}", failure.1));
|
||||
}
|
||||
}
|
||||
let mut status = "Secured".to_owned();
|
||||
|
||||
if failure.0 != subsystem::FAILURE_NONE {
|
||||
status = failure.1;
|
||||
}
|
||||
|
||||
let icon_color = match failure.0 {
|
||||
@@ -291,6 +303,13 @@ pub fn update_icon<R: Runtime>(
|
||||
_ => IconColor::Green,
|
||||
},
|
||||
};
|
||||
|
||||
if let Ok(menu) = build_tray_menu(icon.app_handle(), status.as_ref(), spn_status.as_str()) {
|
||||
if let Err(err) = icon.set_menu(Some(menu)) {
|
||||
error!("failed to set menu on tray icon: {}", err.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
update_icon_color(&icon, icon_color);
|
||||
}
|
||||
|
||||
@@ -391,8 +410,7 @@ pub async fn tray_handler(cli: PortAPI, app: tauri::AppHandle) {
|
||||
match payload.parse::<Subsystem>() {
|
||||
Ok(n) => {
|
||||
subsystems.insert(n.id.clone(), n);
|
||||
|
||||
update_icon(icon.clone(), app.menu(), subsystems.clone(), spn_status.clone());
|
||||
update_icon(icon.clone(), subsystems.clone(), spn_status.clone());
|
||||
},
|
||||
Err(err) => match err {
|
||||
ParseError::Json(err) => {
|
||||
@@ -423,8 +441,7 @@ pub async fn tray_handler(cli: PortAPI, app: tauri::AppHandle) {
|
||||
Ok(value) => {
|
||||
debug!("SPN status update: {}", value.status);
|
||||
spn_status.clone_from(&value.status);
|
||||
|
||||
update_icon(icon.clone(), app.menu(), subsystems.clone(), spn_status.clone());
|
||||
update_icon(icon.clone(), subsystems.clone(), spn_status.clone());
|
||||
},
|
||||
Err(err) => match err {
|
||||
ParseError::Json(err) => {
|
||||
@@ -453,9 +470,7 @@ pub async fn tray_handler(cli: PortAPI, app: tauri::AppHandle) {
|
||||
if let Some((_, payload)) = res {
|
||||
match payload.parse::<BooleanValue>() {
|
||||
Ok(value) => {
|
||||
if let Some(menu) = app.menu() {
|
||||
update_spn_ui_state(menu, value.value.unwrap_or(false));
|
||||
}
|
||||
SPN_STATE.store(value.value.unwrap_or(false), Ordering::Release);
|
||||
},
|
||||
Err(err) => match err {
|
||||
ParseError::Json(err) => {
|
||||
@@ -487,9 +502,6 @@ pub async fn tray_handler(cli: PortAPI, app: tauri::AppHandle) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(menu) = app.menu() {
|
||||
update_spn_ui_state(menu, false);
|
||||
}
|
||||
update_icon_color(&icon, IconColor::Red);
|
||||
}
|
||||
|
||||
@@ -554,22 +566,4 @@ fn save_theme(app: &tauri::AppHandle, mode: dark_light::Mode) {
|
||||
}
|
||||
Err(err) => error!("failed to load config file: {}", err),
|
||||
}
|
||||
if let Some(menu) = app.menu() {
|
||||
update_spn_ui_state(menu, false);
|
||||
}
|
||||
}
|
||||
|
||||
fn update_spn_ui_state<R: Runtime>(menu: Menu<R>, enabled: bool) {
|
||||
if let (Some(MenuItemKind::MenuItem(spn_status)), Some(MenuItemKind::MenuItem(spn_btn))) =
|
||||
(menu.get(SPN_STATUS_KEY), menu.get(SPN_BUTTON_KEY))
|
||||
{
|
||||
if enabled {
|
||||
_ = spn_status.set_text("SPN: Connected");
|
||||
_ = spn_btn.set_text("Disable SPN");
|
||||
} else {
|
||||
_ = spn_status.set_text("SPN: Disabled");
|
||||
_ = spn_btn.set_text("Enable SPN");
|
||||
}
|
||||
SPN_STATE.store(enabled, Ordering::Release);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,6 +178,9 @@ var dataDir
|
||||
RMDir /r /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\exec"
|
||||
RMDir /r /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\logs"
|
||||
|
||||
; Remove PMv1 migration flag
|
||||
Delete /REBOOTOK "$COMMONPROGRAMDATA\Safing\Portmaster\migrated.txt"
|
||||
|
||||
${If} $DeleteAppDataCheckboxState = 1
|
||||
DetailPrint "Deleting the application data..."
|
||||
RMDir /r /REBOOTOK "$COMMONPROGRAMDATA\Portmaster"
|
||||
|
||||
@@ -28,6 +28,9 @@ if [ -d "$OLD_INSTALLATION_DIR" ]; then
|
||||
echo "[ ] V1 migration: Removing V1 shortcuts"
|
||||
rm /etc/xdg/autostart/portmaster_notifier.desktop
|
||||
rm /usr/share/applications/portmaster_notifier.desktop
|
||||
# app V1 shortcut
|
||||
# NOTE: new V2 shortcut registered as "Portmaster.desktop" (first letter uppercase), so we can distinguish between V1 and V2 shortcuts.
|
||||
rm /usr/share/applications/portmaster.desktop
|
||||
|
||||
# Remove V1 files (except configuration)
|
||||
# (keeping V1 configuration for a smooth downgrade, if needed)
|
||||
|
||||
@@ -50,15 +50,19 @@
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# Optional arguments:
|
||||
# -i, --interactive: Can prompt for user input (e.g. when a file is not found in the primary folder but found in the alternate folder)
|
||||
# -v, --version: Explicitly set the version to use for the installer file name
|
||||
# -i: (interactive) Can prompt for user input (e.g. when a file is not found in the primary folder but found in the alternate folder)
|
||||
# -v: (version) Explicitly set the version to use for the installer file name
|
||||
# -e: (erase) Just erase work directories
|
||||
#------------------------------------------------------------------------------
|
||||
param (
|
||||
[Alias('i')]
|
||||
[switch]$interactive,
|
||||
|
||||
[Alias('v')]
|
||||
[string]$version
|
||||
[string]$version,
|
||||
|
||||
[Alias('e')]
|
||||
[switch]$erase
|
||||
)
|
||||
|
||||
# Save the current directory
|
||||
@@ -185,7 +189,18 @@ try {
|
||||
$destinationDir = "desktop/tauri/src-tauri"
|
||||
$binaryDir = "$destinationDir/binary" #portmaster\desktop\tauri\src-tauri\binary
|
||||
$intelDir = "$destinationDir/intel" #portmaster\desktop\tauri\src-tauri\intel
|
||||
$targetDir = "$destinationDir/target/release" #portmaster\desktop\tauri\src-tauri\target\release
|
||||
$targetBase= "$destinationDir/target" #portmaster\desktop\tauri\src-tauri\target
|
||||
$targetDir = "$targetBase/release" #portmaster\desktop\tauri\src-tauri\target\release
|
||||
|
||||
# Erasing work directories
|
||||
Write-Output "[+] Erasing work directories: '$binaryDir', '$intelDir', '$targetBase'"
|
||||
Remove-Item -Recurse -Force -Path $binaryDir -ErrorAction SilentlyContinue
|
||||
Remove-Item -Recurse -Force -Path $intelDir -ErrorAction SilentlyContinue
|
||||
Remove-Item -Recurse -Force -Path $targetBase -ErrorAction SilentlyContinue
|
||||
if ($erase) {
|
||||
Write-Output "[ ] Done"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Copying BINARY FILES
|
||||
Write-Output "`n[+] Copying binary files:"
|
||||
|
||||
@@ -115,7 +115,7 @@ func MakeUpdateConfigs(svcCfg *ServiceConfig) (binaryUpdateConfig, intelUpdateCo
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
binaryUpdateConfig = &updates.Config{
|
||||
Name: "binaries",
|
||||
Name: configure.DefaultBinaryIndexName,
|
||||
Directory: svcCfg.BinDir,
|
||||
DownloadDirectory: filepath.Join(svcCfg.DataDir, "download_binaries"),
|
||||
PurgeDirectory: filepath.Join(svcCfg.BinDir, "upgrade_obsolete_binaries"),
|
||||
@@ -130,7 +130,7 @@ func MakeUpdateConfigs(svcCfg *ServiceConfig) (binaryUpdateConfig, intelUpdateCo
|
||||
Notify: true,
|
||||
}
|
||||
intelUpdateConfig = &updates.Config{
|
||||
Name: "intel",
|
||||
Name: configure.DefaultIntelIndexName,
|
||||
Directory: filepath.Join(svcCfg.DataDir, "intel"),
|
||||
DownloadDirectory: filepath.Join(svcCfg.DataDir, "download_intel"),
|
||||
PurgeDirectory: filepath.Join(svcCfg.DataDir, "upgrade_obsolete_intel"),
|
||||
@@ -146,7 +146,7 @@ func MakeUpdateConfigs(svcCfg *ServiceConfig) (binaryUpdateConfig, intelUpdateCo
|
||||
|
||||
case "linux":
|
||||
binaryUpdateConfig = &updates.Config{
|
||||
Name: "binaries",
|
||||
Name: configure.DefaultBinaryIndexName,
|
||||
Directory: svcCfg.BinDir,
|
||||
DownloadDirectory: filepath.Join(svcCfg.DataDir, "download_binaries"),
|
||||
PurgeDirectory: filepath.Join(svcCfg.DataDir, "upgrade_obsolete_binaries"),
|
||||
@@ -161,7 +161,7 @@ func MakeUpdateConfigs(svcCfg *ServiceConfig) (binaryUpdateConfig, intelUpdateCo
|
||||
Notify: true,
|
||||
}
|
||||
intelUpdateConfig = &updates.Config{
|
||||
Name: "intel",
|
||||
Name: configure.DefaultIntelIndexName,
|
||||
Directory: filepath.Join(svcCfg.DataDir, "intel"),
|
||||
DownloadDirectory: filepath.Join(svcCfg.DataDir, "download_intel"),
|
||||
PurgeDirectory: filepath.Join(svcCfg.DataDir, "upgrade_obsolete_intel"),
|
||||
|
||||
@@ -5,6 +5,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultBinaryIndexName = "Portmaster Binaries"
|
||||
DefaultIntelIndexName = "intel"
|
||||
|
||||
DefaultStableBinaryIndexURLs = []string{
|
||||
"https://updates.safing.io/stable.v3.json",
|
||||
}
|
||||
|
||||
@@ -118,6 +118,14 @@ type Index struct {
|
||||
Artifacts []*Artifact `json:"Artifacts"`
|
||||
|
||||
versionNum *semver.Version
|
||||
|
||||
// isLocallyGenerated indicates whether the index was generated from a local directory.
|
||||
//
|
||||
// When true:
|
||||
// - The `Published` field represents the generation time, not a formal release date.
|
||||
// This timestamp should be ignored when checking for online updates.
|
||||
// - Downgrades from this locally generated version to an online index should be prevented.
|
||||
isLocallyGenerated bool
|
||||
}
|
||||
|
||||
// LoadIndex loads and parses an index from the given filename.
|
||||
@@ -235,6 +243,15 @@ func (index *Index) ShouldUpgradeTo(newIndex *Index) error {
|
||||
case index.Name != newIndex.Name:
|
||||
return errors.New("new index name does not match")
|
||||
|
||||
case index.isLocallyGenerated:
|
||||
if newIndex.versionNum.GreaterThan(index.versionNum) {
|
||||
// Upgrade! (from a locally generated index to an online index)
|
||||
return nil
|
||||
} else {
|
||||
// "Do nothing".
|
||||
return ErrSameIndex
|
||||
}
|
||||
|
||||
case index.Published.After(newIndex.Published):
|
||||
return errors.New("new index is older (time)")
|
||||
|
||||
|
||||
@@ -234,10 +234,11 @@ func GenerateIndexFromDir(sourceDir string, cfg IndexScanConfig) (*Index, error)
|
||||
|
||||
// Create base index.
|
||||
index := &Index{
|
||||
Name: cfg.Name,
|
||||
Version: cfg.Version,
|
||||
Published: time.Now(),
|
||||
versionNum: indexVersion,
|
||||
Name: cfg.Name,
|
||||
Version: cfg.Version,
|
||||
Published: time.Now(),
|
||||
versionNum: indexVersion,
|
||||
isLocallyGenerated: true,
|
||||
}
|
||||
if index.Version == "" && cfg.PrimaryArtifact != "" {
|
||||
pv, ok := artifacts[cfg.PrimaryArtifact]
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/safing/portmaster/base/log"
|
||||
"github.com/safing/portmaster/base/notifications"
|
||||
"github.com/safing/portmaster/base/utils"
|
||||
"github.com/safing/portmaster/service/configure"
|
||||
"github.com/safing/portmaster/service/mgr"
|
||||
)
|
||||
|
||||
@@ -201,6 +202,7 @@ func New(instance instance, name string, cfg Config) (*Updater, error) {
|
||||
module.corruptedInstallation = fmt.Errorf("invalid index: %w", err)
|
||||
}
|
||||
index, err = GenerateIndexFromDir(cfg.Directory, IndexScanConfig{
|
||||
Name: configure.DefaultBinaryIndexName,
|
||||
Version: info.VersionNumber(),
|
||||
})
|
||||
if err == nil && index.init(currentPlatform) == nil {
|
||||
|
||||
@@ -73,6 +73,10 @@ func (u *Updater) upgradeMoveFiles(downloader *Downloader) error {
|
||||
if slices.Contains(u.cfg.Ignore, file.Name()) {
|
||||
continue
|
||||
}
|
||||
// ignore PurgeDirectory itself
|
||||
if strings.EqualFold(u.cfg.PurgeDirectory, filepath.Join(u.cfg.Directory, file.Name())) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Otherwise, move file to purge dir.
|
||||
src := filepath.Join(u.cfg.Directory, file.Name())
|
||||
|
||||
Reference in New Issue
Block a user