mirror of
https://github.com/safing/portmaster
synced 2025-04-14 07:59:11 +00:00
Merge pull request #1821 from safing/feature/installer-migration
Feature/installer migration
This commit is contained in:
commit
731ad885bb
65 changed files with 15744 additions and 22834 deletions
.gitignoreEarthfile
cmds/cmdbase
desktop
angular
tauri
rust-dark-light
src-tauri
Cargo.lockCargo.tomlREADME.md
gen/schemas
tauri.conf.json5templates
NSIS_Simple_Service_Plugin_Unicode_1.30
nsis
nsis_install_hooks.nshservice.wxswix
packaging
service
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -4,6 +4,7 @@ dist/
|
|||
|
||||
# Dist dir
|
||||
dist
|
||||
packaging/_precompiled/
|
||||
|
||||
# Custom dev deops
|
||||
go.mod.*
|
||||
|
@ -52,3 +53,7 @@ go.work.sum
|
|||
# Kext releases
|
||||
windows_kext/release/kext_release_*.zip
|
||||
windows_core_dll/.vs/windows_core_dll
|
||||
|
||||
#windows_core_dll
|
||||
windows_core_dll/x64/
|
||||
windows_core_dll/portmaster-core/x64/
|
||||
|
|
166
Earthfile
166
Earthfile
|
@ -1,9 +1,13 @@
|
|||
VERSION --arg-scope-and-set --global-cache 0.8
|
||||
VERSION 0.8
|
||||
|
||||
# Custom argument: "custom_version" to manually set the version of the build (and ignore Git Tag value)
|
||||
# Usage example: earthly --build-arg custom_version="1.2.3" +<target>
|
||||
ARG --global custom_version = ""
|
||||
|
||||
ARG --global go_version = 1.22
|
||||
ARG --global node_version = 18
|
||||
ARG --global rust_version = 1.79
|
||||
ARG --global tauri_version = "2.0.1"
|
||||
ARG --global rust_version = 1.81
|
||||
ARG --global tauri_version = "2.2.5"
|
||||
ARG --global golangci_lint_version = 1.57.1
|
||||
|
||||
ARG --global go_builder_image = "golang:${go_version}-alpine"
|
||||
|
@ -131,27 +135,9 @@ go-base:
|
|||
|
||||
# Copy the full repo, as Go embeds whether the state is clean.
|
||||
COPY . .
|
||||
|
||||
LET version = "$(git tag --points-at || true)"
|
||||
IF [ -z "${version}" ]
|
||||
LET dev_version = "$(git describe --tags --first-parent --abbrev=0 || true)"
|
||||
IF [ -n "${dev_version}" ]
|
||||
SET version = "${dev_version}_dev_build"
|
||||
END
|
||||
END
|
||||
IF [ -z "${version}" ]
|
||||
SET version = "dev_build"
|
||||
END
|
||||
ENV VERSION="${version}"
|
||||
RUN echo "Version: $VERSION"
|
||||
|
||||
LET source = $( ( git remote -v | cut -f2 | cut -d" " -f1 | head -n 1 ) || echo "unknown" )
|
||||
ENV SOURCE="${source}"
|
||||
RUN echo "Source: $SOURCE"
|
||||
|
||||
LET build_time = $(date -u "+%Y-%m-%dT%H:%M:%SZ" || echo "unknown")
|
||||
ENV BUILD_TIME = "${build_time}"
|
||||
RUN echo "Build Time: $BUILD_TIME"
|
||||
|
||||
# Set version information: VERSION, SOURCE, BUILD_TIME and VERSION_SemVer
|
||||
DO +SET_VERSION_INFO
|
||||
|
||||
# Explicitly cache here.
|
||||
SAVE IMAGE --cache-hint
|
||||
|
@ -426,7 +412,7 @@ rust-base:
|
|||
DO rust+INIT --keep_fingerprints=true
|
||||
|
||||
# For now we need tauri-cli 2.0.0 for bulding
|
||||
DO rust+CARGO --args="install tauri-cli --version 2.1.0 --locked"
|
||||
DO rust+CARGO --args="install tauri-cli --version 2.2.7 --locked"
|
||||
|
||||
# Explicitly cache here.
|
||||
SAVE IMAGE --cache-hint
|
||||
|
@ -450,7 +436,7 @@ tauri-src:
|
|||
|
||||
tauri-build:
|
||||
FROM +tauri-src
|
||||
|
||||
|
||||
ARG --required target
|
||||
|
||||
ARG output=".*/release/([^\./]+|([^\./]+\.(dll|exe)))"
|
||||
|
@ -459,6 +445,8 @@ tauri-build:
|
|||
|
||||
DO rust+SET_CACHE_MOUNTS_ENV
|
||||
RUN rustup target add "${target}"
|
||||
|
||||
# Build
|
||||
RUN --mount=$EARTHLY_RUST_TARGET_CACHE cargo tauri build --ci --target="${target}" --no-bundle
|
||||
DO rust+COPY_OUTPUT --output="${output}"
|
||||
|
||||
|
@ -535,35 +523,44 @@ release-prep:
|
|||
|
||||
# Build update manager
|
||||
COPY (+go-build/output/updatemgr --GOARCH=amd64 --GOOS=linux --CMDS=updatemgr) ./updatemgr
|
||||
|
||||
# Get binary artifacts from current release
|
||||
RUN mkdir -p ./output/download/windows_amd64 && ./updatemgr download https://updates.safing.io/stable.v3.json --platform windows_amd64 ./output/download/windows_amd64
|
||||
|
||||
# Copy required artifacts
|
||||
RUN cp ./output/download/windows_amd64/portmaster-kext.sys ./output/binary/windows_amd64/portmaster-kext.sys
|
||||
RUN cp ./output/download/windows_amd64/portmaster-kext.pdb ./output/binary/windows_amd64/portmaster-kext.pdb
|
||||
RUN cp ./output/download/windows_amd64/portmaster-core.dll ./output/binary/windows_amd64/portmaster-core.dll
|
||||
|
||||
# Create new binary index from artifacts
|
||||
RUN ./updatemgr scan --dir "./output/binary" > ./output/binary/index.json
|
||||
|
||||
# Get intel index and assets
|
||||
# Get "portmaster-kext.sys" and "portmaster-core.dll" from current stable release
|
||||
RUN mkdir -p ./output/downloaded/windows_amd64 && ./updatemgr download https://updates.safing.io/stable.v3.json --platform windows_amd64 ./output/downloaded/windows_amd64
|
||||
RUN find ./output/downloaded/windows_amd64 -type f ! -name "portmaster-kext.sys" ! -name "portmaster-core.dll" -delete # We are only interested in the KEXT and core DLL. Remove the rest.
|
||||
# Get intel artifacts
|
||||
RUN mkdir -p ./output/intel && ./updatemgr download https://updates.safing.io/intel.v3.json ./output/intel
|
||||
|
||||
# Save all artifacts to output folder
|
||||
SAVE ARTIFACT --if-exists --keep-ts "output/binary/index.json" AS LOCAL "${outputDir}/binary/index.json"
|
||||
SAVE ARTIFACT --if-exists --keep-ts "output/binary/all/*" AS LOCAL "${outputDir}/binary/all/"
|
||||
SAVE ARTIFACT --if-exists --keep-ts "output/binary/linux_amd64/*" AS LOCAL "${outputDir}/binary/linux_amd64/"
|
||||
SAVE ARTIFACT --if-exists --keep-ts "output/binary/windows_amd64/*" AS LOCAL "${outputDir}/binary/windows_amd64/"
|
||||
SAVE ARTIFACT --if-exists --keep-ts "output/intel/*" AS LOCAL "${outputDir}/intel/"
|
||||
|
||||
# Save all artifacts to output folder (on host)
|
||||
SAVE ARTIFACT --keep-ts "output/binary/all/*" AS LOCAL "${outputDir}/binary/all/"
|
||||
SAVE ARTIFACT --keep-ts "output/binary/linux_amd64/*" AS LOCAL "${outputDir}/binary/linux_amd64/"
|
||||
SAVE ARTIFACT --keep-ts "output/binary/windows_amd64/*" AS LOCAL "${outputDir}/binary/windows_amd64/"
|
||||
SAVE ARTIFACT --keep-ts "output/intel/*" AS LOCAL "${outputDir}/intel/"
|
||||
SAVE ARTIFACT --keep-ts "output/downloaded/*" AS LOCAL "${outputDir}/downloaded/" # KEXT and core DLL: artifacts from the current stable release
|
||||
|
||||
# Save all artifacts to the container output folder so other containers can access it.
|
||||
SAVE ARTIFACT --if-exists --keep-ts "output/binary/index.json" "output/binary/index.json"
|
||||
SAVE ARTIFACT --if-exists --keep-ts "output/binary/all/*" "output/binary/all/"
|
||||
SAVE ARTIFACT --if-exists --keep-ts "output/binary/linux_amd64/*" "output/binary/linux_amd64/"
|
||||
SAVE ARTIFACT --if-exists --keep-ts "output/binary/windows_amd64/*" "output/binary/windows_amd64/"
|
||||
SAVE ARTIFACT --if-exists --keep-ts "output/intel/*" "output/intel/"
|
||||
SAVE ARTIFACT --if-exists --keep-ts "output/download/*" "output/download/"
|
||||
SAVE ARTIFACT --keep-ts "output/binary/all/*" "output/binary/all/"
|
||||
SAVE ARTIFACT --keep-ts "output/binary/linux_amd64/*" "output/binary/linux_amd64/"
|
||||
SAVE ARTIFACT --keep-ts "output/binary/windows_amd64/*" "output/binary/windows_amd64/"
|
||||
SAVE ARTIFACT --keep-ts "output/intel/*" "output/intel/"
|
||||
SAVE ARTIFACT --keep-ts "output/downloaded/*" "output/downloaded/"
|
||||
|
||||
# IMPORTANT: COPYING PRECOMPILED LOCAL FILES!
|
||||
# If "packaging/_precompiled" foledr exists, it's contents has priority to be used; it's files will overwrite the ones from the build!
|
||||
# Expected structure:
|
||||
# - packaging/_precompiled/binary/...
|
||||
# - packaging/_precompiled/intel
|
||||
# Careful! If there are any files in the '_precompiled/intel' folder, the final 'intel/index.json' may be broken due to incorrect hash values!
|
||||
COPY --if-exists --keep-ts ./packaging/_precompiled/binary ./packaging/precompiled/binary
|
||||
COPY --if-exists --keep-ts ./packaging/_precompiled/intel ./packaging/precompiled/intel
|
||||
IF --no-cache [ -d ./packaging/precompiled ]
|
||||
RUN --no-cache echo "[ !!! ATTENTION !!! ] PRECOMPILED FILES IN USE:" && find ./packaging/precompiled -type f;
|
||||
IF --no-cache [ -d ./packaging/precompiled/intel ]
|
||||
RUN --no-cache echo "[!!! ATTENTION !!!] ENSURE THAT 'intel/index.json' CONTAINS THE CORRECT HASHES!"
|
||||
END
|
||||
SAVE ARTIFACT --if-exists --keep-ts "packaging/precompiled/intel/*" AS LOCAL "${outputDir}/intel/" # save to host
|
||||
SAVE ARTIFACT --if-exists --keep-ts "packaging/precompiled/binary/*" AS LOCAL "${outputDir}/binary/" # save to host
|
||||
SAVE ARTIFACT --if-exists --keep-ts "packaging/precompiled/intel/*" "output/intel/" # save to container (so other containers can access it)
|
||||
SAVE ARTIFACT --if-exists --keep-ts "packaging/precompiled/binary/*" "output/binary/" # save to container (so other containers can access it)
|
||||
END
|
||||
|
||||
installer-linux:
|
||||
FROM +rust-base
|
||||
|
@ -586,7 +583,6 @@ installer-linux:
|
|||
COPY (+release-prep/output/binary/linux_amd64/portmaster) ./target/${target}/release/portmaster
|
||||
|
||||
RUN mkdir -p binary
|
||||
COPY (+release-prep/output/binary/index.json) ./binary/index.json
|
||||
COPY (+release-prep/output/binary/linux_amd64/portmaster-core) ./binary/portmaster-core
|
||||
COPY (+release-prep/output/binary/all/portmaster.zip) ./binary/portmaster.zip
|
||||
COPY (+release-prep/output/binary/all/assets.zip) ./binary/assets.zip
|
||||
|
@ -595,6 +591,11 @@ installer-linux:
|
|||
RUN mkdir -p intel
|
||||
COPY (+release-prep/output/intel/*) ./intel/
|
||||
|
||||
# Init version information: VERSION, SOURCE, BUILD_TIME and VERSION_SemVer
|
||||
DO +SET_VERSION_INFO
|
||||
# Set version in Cargo.toml if it's a valid SemVer (required for using in the installer file names)
|
||||
RUN if [ -n "$VERSION_SemVer" ]; then sed -i 's/^version = ".*"/version = "'"$VERSION_SemVer"'"/g' Cargo.toml; fi
|
||||
|
||||
# build the installers
|
||||
RUN cargo tauri bundle --ci --target="${target}"
|
||||
|
||||
|
@ -697,3 +698,62 @@ BIN_EXT:
|
|||
SET binext=".exe"
|
||||
END
|
||||
ENV BINEXT="${goos}"
|
||||
|
||||
# Function to set the version-related environment variables (variables: VERSION, SOURCE, BUILD_TIME and VERSION_SemVer)
|
||||
# Call example:
|
||||
# DO +SET_VERSION_INFO
|
||||
SET_VERSION_INFO:
|
||||
FUNCTION
|
||||
ARG gitDir="/tmp/git-info"
|
||||
|
||||
# Check if already initialized and skip the rest if true
|
||||
IF [ -n "$BUILD_TIME" ]
|
||||
#RUN echo "Version info already initialized"
|
||||
ELSE
|
||||
# Make sure git is installed in the image
|
||||
RUN which git || apk add --no-cache git
|
||||
# Create a temporary directory for git information only
|
||||
RUN mkdir -p ${gitDir}
|
||||
# Copy only the .git directory to the temporary location
|
||||
COPY --dir .git ${gitDir}/.git
|
||||
|
||||
# Check if custom version was provided via command line
|
||||
IF [ -n "$custom_version" ]
|
||||
ENV VERSION="${custom_version}"
|
||||
RUN echo "Using custom version from command line: $VERSION"
|
||||
ELSE
|
||||
# Get version from git tags without changing workdir
|
||||
LET version = "$(git --git-dir=${gitDir}/.git tag --points-at || true)"
|
||||
IF [ -z "${version}" ]
|
||||
LET dev_version = "$(git --git-dir=${gitDir}/.git describe --tags --first-parent --abbrev=0 || true)"
|
||||
IF [ -n "${dev_version}" ]
|
||||
SET version = "${dev_version}_dev_build"
|
||||
END
|
||||
END
|
||||
IF [ -z "${version}" ]
|
||||
SET version = "dev_build"
|
||||
END
|
||||
ENV VERSION="${version}"
|
||||
RUN echo "Version: $VERSION"
|
||||
END
|
||||
|
||||
# Create cleaned version without 'v' prefix and without suffix starting with '_'
|
||||
# Only set VERSION_SemVer if it matches semantic versioning format
|
||||
LET version_clean = "$(echo "${VERSION}" | sed -E 's/^[vV]//' | sed -E 's/_.*$//')"
|
||||
IF [ $(echo "${version_clean}" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+([.-].*)?$') ]
|
||||
ENV VERSION_SemVer="${version_clean}"
|
||||
RUN echo "VERSION_SemVer: $VERSION_SemVer"
|
||||
ELSE
|
||||
RUN echo "VERSION_SemVer: [Empty - not a valid SemVer in Git Tag] - !!! WARNING !!!"
|
||||
END
|
||||
|
||||
# Get source information without changing workdir
|
||||
LET source = "$( (git --git-dir=${gitDir}/.git remote -v | cut -f2 | cut -d" " -f1 | head -n 1) || echo "unknown" )"
|
||||
ENV SOURCE="${source}"
|
||||
RUN echo "Source: $SOURCE"
|
||||
|
||||
# Get build time
|
||||
LET build_time = "$(date -u "+%Y-%m-%dT%H:%M:%SZ" || echo "unknown")"
|
||||
ENV BUILD_TIME = "${build_time}"
|
||||
RUN echo "Build Time: $BUILD_TIME"
|
||||
END
|
|
@ -123,9 +123,13 @@ waitSignal:
|
|||
}
|
||||
}
|
||||
|
||||
// Wait for shutdown to finish.
|
||||
// Trigger shutdown.
|
||||
s.instance.Shutdown()
|
||||
|
||||
// Notify the service host that service is in shutting down state.
|
||||
changes <- svc.Status{State: svc.StopPending}
|
||||
|
||||
// Wait for shutdown to finish.
|
||||
// Catch signals during shutdown.
|
||||
// Force exit after 5 interrupts.
|
||||
forceCnt := 5
|
||||
|
|
25639
desktop/angular/package-lock.json
generated
25639
desktop/angular/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"name": "portmaster",
|
||||
"version": "0.8.11",
|
||||
"version": "2.0.1",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "npm install && npm run build-libs:dev && ng serve --proxy-config ./proxy.json",
|
||||
"build-libs": "NODE_ENV=production ng build --configuration production @safing/ui && NODE_ENV=production ng build --configuration production @safing/portmaster-api",
|
||||
"build-libs": "cross-env NODE_ENV=production ng build --configuration production @safing/ui && cross-env NODE_ENV=production ng build --configuration production @safing/portmaster-api",
|
||||
"build-libs:dev": "ng build --configuration development @safing/ui && ng build --configuration development @safing/portmaster-api",
|
||||
"serve": "npm run build-libs:dev && ng serve --proxy-config ./proxy.json",
|
||||
"build:dev": "npm run build-libs:dev && ng build",
|
||||
|
@ -12,10 +12,10 @@
|
|||
"lint": "ng lint",
|
||||
"e2e": "ng e2e",
|
||||
"zip-dist": "node pack.js",
|
||||
"chrome-extension": "NODE_ENV=production ng build --configuration production portmaster-chrome-extension",
|
||||
"chrome-extension": "cross-env NODE_ENV=production ng build --configuration production portmaster-chrome-extension",
|
||||
"chrome-extension:dev": "ng build --configuration development portmaster-chrome-extension --watch",
|
||||
"build": "npm run build-libs && NODE_ENV=production ng build --configuration production --base-href /ui/modules/portmaster/",
|
||||
"build-tauri": "npm run build-libs && NODE_ENV=production ng build --configuration production tauri-builtin",
|
||||
"build-tauri": "npm run build-libs && cross-env NODE_ENV=production ng build --configuration production tauri-builtin",
|
||||
"serve-tauri-builtin": "ng serve tauri-builtin --port 4100",
|
||||
"serve-app": "ng serve --port 4200 --proxy-config ./proxy.json",
|
||||
"tauri-dev": "npm install && run-s build-libs:dev && run-p serve-app serve-tauri-builtin"
|
||||
|
@ -32,6 +32,7 @@
|
|||
"@angular/platform-browser": "^16.0.1",
|
||||
"@angular/platform-browser-dynamic": "^16.0.1",
|
||||
"@angular/router": "^16.0.1",
|
||||
"@ctrl/tinycolor": "^4.1.0",
|
||||
"@fortawesome/angular-fontawesome": "^0.13.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.4.0",
|
||||
|
@ -84,6 +85,7 @@
|
|||
"@types/whatwg-encoding": "^2.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.6",
|
||||
"@typescript-eslint/parser": "^5.59.6",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.40.0",
|
||||
"jasmine-core": "^5.0.0",
|
||||
"jasmine-spec-reporter": "^7.0.0",
|
||||
|
|
|
@ -750,7 +750,7 @@ export class PortapiService {
|
|||
// for data-manipulating methods success
|
||||
// ends the stream.
|
||||
if (data.type === 'success') {
|
||||
observer.next();
|
||||
observer.next(null as any);
|
||||
observer.complete();
|
||||
return;
|
||||
}
|
||||
|
|
4
desktop/tauri/rust-dark-light/.gitignore
vendored
Normal file
4
desktop/tauri/rust-dark-light/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/target
|
||||
/examples/*/target
|
||||
Cargo.lock
|
||||
.vscode
|
34
desktop/tauri/rust-dark-light/Cargo.toml
Normal file
34
desktop/tauri/rust-dark-light/Cargo.toml
Normal file
|
@ -0,0 +1,34 @@
|
|||
[package]
|
||||
name = "dark-light"
|
||||
version = "1.1.1"
|
||||
authors = ["Corey Farwell <coreyf@rwell.org>"]
|
||||
edition = "2018"
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/frewsxcv/rust-dark-light"
|
||||
description = "Detect if dark mode or light mode is enabled"
|
||||
readme = "README.md"
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
futures = "0.3.30"
|
||||
anyhow = "1.0.79"
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.23.0", features = ["full"] }
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd", target_os = "openbsd"))'.dependencies]
|
||||
detect-desktop-environment = "1.0.0"
|
||||
dconf_rs = "0.3"
|
||||
zbus = "3.0"
|
||||
rust-ini = "0.20"
|
||||
ashpd = "0.7.0"
|
||||
xdg = "2.4.1"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winreg = "0.52.0"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
objc = "0.2"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
web-sys = { version = "0.3", features = ["MediaQueryList", "Window"] }
|
39
desktop/tauri/rust-dark-light/README.md
Normal file
39
desktop/tauri/rust-dark-light/README.md
Normal file
|
@ -0,0 +1,39 @@
|
|||
# rust-dark-light
|
||||
|
||||
Rust crate to detect if dark mode or light mode is enabled. Supports macOS, Windows, Linux, BSDs, and WASM. On Linux and BSDs, first the XDG Desktop Portal dbus API is checked for the `color-scheme` preference, which works in Flatpak sandboxes without needing filesystem access. If that does not work, fallback methods are used for KDE, GNOME, Cinnamon, MATE, XFCE, and Unity.
|
||||
|
||||
[API Documentation](https://docs.rs/dark-light/)
|
||||
|
||||
## Usage
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let mode = dark_light::detect();
|
||||
|
||||
match mode {
|
||||
// Dark mode
|
||||
dark_light::Mode::Dark => {},
|
||||
// Light mode
|
||||
dark_light::Mode::Light => {},
|
||||
// Unspecified
|
||||
dark_light::Mode::Default => {},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```
|
||||
cargo run --example detect
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
||||
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
|
5
desktop/tauri/rust-dark-light/build.rs
Normal file
5
desktop/tauri/rust-dark-light/build.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
fn main() {
|
||||
if let Ok("apple") = std::env::var("CARGO_CFG_TARGET_VENDOR").as_deref() {
|
||||
println!("cargo:rustc-link-lib=framework=AppKit");
|
||||
}
|
||||
}
|
92
desktop/tauri/rust-dark-light/src/freedesktop.rs
Normal file
92
desktop/tauri/rust-dark-light/src/freedesktop.rs
Normal file
|
@ -0,0 +1,92 @@
|
|||
use detect_desktop_environment::DesktopEnvironment;
|
||||
use ini::Ini;
|
||||
use std::path::{Path, PathBuf};
|
||||
use zbus::blocking::Connection;
|
||||
|
||||
use crate::Mode;
|
||||
|
||||
const XDG_KDEGLOBALS: &str = "/etc/xdg/kdeglobals";
|
||||
|
||||
fn get_freedesktop_color_scheme() -> Option<Mode> {
|
||||
let conn = Connection::session();
|
||||
if conn.is_err() {
|
||||
return None;
|
||||
}
|
||||
let reply = conn.unwrap().call_method(
|
||||
Some("org.freedesktop.portal.Desktop"),
|
||||
"/org/freedesktop/portal/desktop",
|
||||
Some("org.freedesktop.portal.Settings"),
|
||||
"Read",
|
||||
&("org.freedesktop.appearance", "color-scheme"),
|
||||
);
|
||||
if let Ok(reply) = &reply {
|
||||
let theme = reply.body().deserialize::<u32>();
|
||||
if theme.is_err() {
|
||||
return None;
|
||||
}
|
||||
|
||||
match theme.unwrap() {
|
||||
1 => Some(Mode::Dark),
|
||||
2 => Some(Mode::Light),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn detect_gtk(pattern: &str) -> Mode {
|
||||
match dconf_rs::get_string(pattern) {
|
||||
Ok(theme) => Mode::from(theme.to_lowercase().contains("dark")),
|
||||
Err(_) => Mode::Light,
|
||||
}
|
||||
}
|
||||
|
||||
fn detect_kde(path: &str) -> Mode {
|
||||
match Ini::load_from_file(path) {
|
||||
Ok(cfg) => {
|
||||
let section = match cfg.section(Some("Colors:Window")) {
|
||||
Some(section) => section,
|
||||
None => return Mode::Light,
|
||||
};
|
||||
let values = match section.get("BackgroundNormal") {
|
||||
Some(string) => string,
|
||||
None => return Mode::Light,
|
||||
};
|
||||
let rgb = values
|
||||
.split(',')
|
||||
.map(|s| s.parse::<u32>().unwrap_or(255))
|
||||
.collect::<Vec<u32>>();
|
||||
let rgb = if rgb.len() > 2 {
|
||||
rgb
|
||||
} else {
|
||||
vec![255, 255, 255]
|
||||
};
|
||||
let (r, g, b) = (rgb[0], rgb[1], rgb[2]);
|
||||
Mode::rgb(r, g, b)
|
||||
}
|
||||
Err(_) => Mode::Light,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn detect() -> Mode {
|
||||
match get_freedesktop_color_scheme() {
|
||||
Some(mode) => mode,
|
||||
// Other desktop environments are still being worked on, fow now, only the following implementations work.
|
||||
None => match DesktopEnvironment::detect() {
|
||||
DesktopEnvironment::Kde => {
|
||||
let path = if Path::new(XDG_KDEGLOBALS).exists() {
|
||||
PathBuf::from(XDG_KDEGLOBALS)
|
||||
} else {
|
||||
dirs::home_dir().unwrap().join(".config/kdeglobals")
|
||||
};
|
||||
detect_kde(path.to_str().unwrap())
|
||||
}
|
||||
DesktopEnvironment::Cinnamon => detect_gtk("/org/cinnamon/desktop/interface/gtk-theme"),
|
||||
DesktopEnvironment::Gnome => detect_gtk("/org/gnome/desktop/interface/gtk-theme"),
|
||||
DesktopEnvironment::Mate => detect_gtk("/org/mate/desktop/interface/gtk-theme"),
|
||||
DesktopEnvironment::Unity => detect_gtk("/org/gnome/desktop/interface/gtk-theme"),
|
||||
_ => Mode::Default,
|
||||
},
|
||||
}
|
||||
}
|
73
desktop/tauri/rust-dark-light/src/lib.rs
Normal file
73
desktop/tauri/rust-dark-light/src/lib.rs
Normal file
|
@ -0,0 +1,73 @@
|
|||
//! Detect if dark mode or light mode is enabled.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! ```
|
||||
//! let mode = dark_light::detect();
|
||||
//!
|
||||
//! match mode {
|
||||
//! // Dark mode
|
||||
//! dark_light::Mode::Dark => {},
|
||||
//! // Light mode
|
||||
//! dark_light::Mode::Light => {},
|
||||
//! // Unspecified
|
||||
//! dark_light::Mode::Default => {},
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
mod platforms;
|
||||
use platforms::platform;
|
||||
|
||||
mod utils;
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
use utils::rgb::Rgb;
|
||||
|
||||
/// Enum representing dark mode, light mode, or unspecified.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Mode {
|
||||
/// Dark mode
|
||||
Dark,
|
||||
/// Light mode
|
||||
Light,
|
||||
/// Unspecified
|
||||
Default,
|
||||
}
|
||||
|
||||
impl Mode {
|
||||
#[allow(dead_code)]
|
||||
fn from_bool(b: bool) -> Self {
|
||||
if b {
|
||||
Mode::Dark
|
||||
} else {
|
||||
Mode::Light
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
/// Convert an RGB color to [`Mode`]. The color is converted to grayscale, and if the grayscale value is less than 192, [`Mode::Dark`] is returned. Otherwise, [`Mode::Light`] is returned.
|
||||
fn from_rgb(rgb: Rgb) -> Self {
|
||||
let window_background_gray = (rgb.0 * 11 + rgb.1 * 16 + rgb.2 * 5) / 32;
|
||||
if window_background_gray < 192 {
|
||||
Self::Dark
|
||||
} else {
|
||||
Self::Light
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Detect if light mode or dark mode is enabled. If the mode can’t be detected, fall back to [`Mode::Default`].
|
||||
pub use platform::detect::detect;
|
||||
/// Notifies the user if the system theme has been changed.
|
||||
pub use platform::notify::subscribe;
|
|
@ -0,0 +1,47 @@
|
|||
use detect_desktop_environment::DesktopEnvironment;
|
||||
|
||||
use crate::Mode;
|
||||
|
||||
use super::{dconf_detect, gsetting_detect, kde_detect, CINNAMON, GNOME, MATE};
|
||||
|
||||
pub fn detect() -> Mode {
|
||||
NonFreeDesktop::detect()
|
||||
}
|
||||
|
||||
/// Detects the color scheme on a platform.
|
||||
trait ColorScheme {
|
||||
fn detect() -> Mode;
|
||||
}
|
||||
|
||||
/// Represents the FreeDesktop platform.
|
||||
struct FreeDesktop;
|
||||
|
||||
/// Represents non FreeDesktop platforms.
|
||||
struct NonFreeDesktop;
|
||||
|
||||
/// Detects the color scheme on FreeDesktop platforms. It makes use of the DBus interface.
|
||||
impl ColorScheme for FreeDesktop {
|
||||
fn detect() -> Mode {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Detects the color scheme on non FreeDesktop platforms, having a custom implementation for each desktop environment.
|
||||
impl ColorScheme for NonFreeDesktop {
|
||||
fn detect() -> Mode {
|
||||
match DesktopEnvironment::detect() {
|
||||
Some(mode) => match mode {
|
||||
DesktopEnvironment::Kde => match kde_detect() {
|
||||
Ok(mode) => mode,
|
||||
Err(_) => Mode::Default,
|
||||
},
|
||||
DesktopEnvironment::Cinnamon => dconf_detect(CINNAMON),
|
||||
DesktopEnvironment::Gnome => gsetting_detect(),
|
||||
DesktopEnvironment::Mate => dconf_detect(MATE),
|
||||
DesktopEnvironment::Unity => dconf_detect(GNOME),
|
||||
_ => Mode::Default,
|
||||
},
|
||||
None => Mode::Default,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
use std::{process::Command, str::FromStr};
|
||||
|
||||
use anyhow::Context;
|
||||
use ini::Ini;
|
||||
|
||||
use crate::{utils::rgb::Rgb, Mode};
|
||||
|
||||
pub mod detect;
|
||||
pub mod notify;
|
||||
|
||||
const MATE: &str = "/org/mate/desktop/interface/gtk-theme";
|
||||
const GNOME: &str = "/org/gnome/desktop/interface/gtk-theme";
|
||||
const CINNAMON: &str = "/org/cinnamon/desktop/interface/gtk-theme";
|
||||
|
||||
fn dconf_detect(path: &str) -> Mode {
|
||||
match dconf_rs::get_string(path) {
|
||||
Ok(theme) => {
|
||||
println!("dconf output: {}", theme);
|
||||
if theme.is_empty() {
|
||||
Mode::Default
|
||||
} else {
|
||||
if theme.to_lowercase().contains("dark") {
|
||||
Mode::Dark
|
||||
} else {
|
||||
Mode::Light
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => Mode::Default,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gsetting_detect() -> Mode {
|
||||
let mode = match Command::new("gsettings")
|
||||
.arg("get")
|
||||
.arg("org.gnome.desktop.interface")
|
||||
.arg("color-scheme")
|
||||
.output()
|
||||
{
|
||||
Ok(output) => {
|
||||
if let Ok(scheme) = String::from_utf8(output.stdout) {
|
||||
if scheme.contains("prefer-dark") {
|
||||
Mode::Dark
|
||||
} else if scheme.contains("prefer-light") {
|
||||
Mode::Dark
|
||||
} else {
|
||||
Mode::Default
|
||||
}
|
||||
} else {
|
||||
Mode::Default
|
||||
}
|
||||
}
|
||||
Err(_) => Mode::Default,
|
||||
};
|
||||
|
||||
// Fallback to dconf
|
||||
if mode == Mode::Default {
|
||||
return dconf_detect(GNOME);
|
||||
}
|
||||
|
||||
mode
|
||||
}
|
||||
|
||||
fn kde_detect() -> anyhow::Result<Mode> {
|
||||
let xdg = xdg::BaseDirectories::new()?;
|
||||
let path = xdg
|
||||
.find_config_file("kdeglobals")
|
||||
.context("Path not found")?;
|
||||
let cfg = Ini::load_from_file(path)?;
|
||||
let properties = cfg
|
||||
.section(Some("Colors:Window"))
|
||||
.context("Failed to get section Colors:Window")?;
|
||||
let background = properties
|
||||
.get("BackgroundNormal")
|
||||
.context("Failed to get BackgroundNormal inside Colors:Window")?;
|
||||
let rgb = Rgb::from_str(background).unwrap();
|
||||
Ok(Mode::from_rgb(rgb))
|
||||
}
|
||||
|
||||
impl From<ashpd::desktop::settings::ColorScheme> for Mode {
|
||||
fn from(value: ashpd::desktop::settings::ColorScheme) -> Self {
|
||||
match value {
|
||||
ashpd::desktop::settings::ColorScheme::NoPreference => Mode::Default,
|
||||
ashpd::desktop::settings::ColorScheme::PreferDark => Mode::Dark,
|
||||
ashpd::desktop::settings::ColorScheme::PreferLight => Mode::Light,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
use ashpd::desktop::settings::{ColorScheme, Settings};
|
||||
use futures::{stream, Stream, StreamExt};
|
||||
use std::task::Poll;
|
||||
|
||||
use crate::{detect, Mode};
|
||||
|
||||
pub async fn subscribe() -> anyhow::Result<impl Stream<Item = Mode> + Send> {
|
||||
let stream = if get_freedesktop_color_scheme().await.is_ok() {
|
||||
let proxy = Settings::new().await?;
|
||||
proxy
|
||||
.receive_color_scheme_changed()
|
||||
.await?
|
||||
.map(Mode::from)
|
||||
.boxed()
|
||||
} else {
|
||||
let mut last_mode = detect();
|
||||
stream::poll_fn(move |ctx| -> Poll<Option<Mode>> {
|
||||
let current_mode = detect();
|
||||
if current_mode != last_mode {
|
||||
last_mode = current_mode;
|
||||
Poll::Ready(Some(current_mode))
|
||||
} else {
|
||||
ctx.waker().wake_by_ref();
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.boxed()
|
||||
};
|
||||
|
||||
Ok(stream)
|
||||
}
|
||||
|
||||
async fn get_freedesktop_color_scheme() -> anyhow::Result<Mode> {
|
||||
let proxy = Settings::new().await?;
|
||||
let color_scheme = proxy.color_scheme().await?;
|
||||
let mode = match color_scheme {
|
||||
ColorScheme::PreferDark => Mode::Dark,
|
||||
ColorScheme::PreferLight => Mode::Light,
|
||||
ColorScheme::NoPreference => Mode::Default,
|
||||
};
|
||||
Ok(mode)
|
||||
}
|
56
desktop/tauri/rust-dark-light/src/platforms/macos/detect.rs
Normal file
56
desktop/tauri/rust-dark-light/src/platforms/macos/detect.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Dark/light mode detection on macOS.
|
||||
// Written with help from Ryan McGrath (https://rymc.io/).
|
||||
|
||||
use crate::Mode;
|
||||
use objc::runtime::Object;
|
||||
use objc::{class, msg_send, sel, sel_impl};
|
||||
|
||||
extern "C" {
|
||||
static NSAppearanceNameAqua: *const Object;
|
||||
static NSAppearanceNameAccessibilityHighContrastAqua: *const Object;
|
||||
static NSAppearanceNameDarkAqua: *const Object;
|
||||
static NSAppearanceNameAccessibilityHighContrastDarkAqua: *const Object;
|
||||
}
|
||||
|
||||
fn is_dark_mode_enabled() -> bool {
|
||||
unsafe {
|
||||
let mut appearance: *const Object = msg_send![class!(NSAppearance), currentAppearance];
|
||||
if appearance.is_null() {
|
||||
appearance = msg_send![class!(NSApp), effectiveAppearance];
|
||||
}
|
||||
|
||||
let objects = [
|
||||
NSAppearanceNameAqua,
|
||||
NSAppearanceNameAccessibilityHighContrastAqua,
|
||||
NSAppearanceNameDarkAqua,
|
||||
NSAppearanceNameAccessibilityHighContrastDarkAqua,
|
||||
];
|
||||
let names: *const Object = msg_send![
|
||||
class!(NSArray),
|
||||
arrayWithObjects:objects.as_ptr()
|
||||
count:objects.len()
|
||||
];
|
||||
|
||||
// `bestMatchFromAppearancesWithNames` is only available in macOS 10.14+.
|
||||
// Gracefully handle earlier versions.
|
||||
let responds_to_selector: objc::runtime::BOOL = msg_send![
|
||||
appearance,
|
||||
respondsToSelector: sel!(bestMatchFromAppearancesWithNames:)
|
||||
];
|
||||
if responds_to_selector == objc::runtime::NO {
|
||||
return false;
|
||||
}
|
||||
|
||||
let style: *const Object = msg_send![
|
||||
appearance,
|
||||
bestMatchFromAppearancesWithNames:&*names
|
||||
];
|
||||
|
||||
style == NSAppearanceNameDarkAqua
|
||||
|| style == NSAppearanceNameAccessibilityHighContrastDarkAqua
|
||||
}
|
||||
}
|
||||
|
||||
pub fn detect() -> crate::Mode {
|
||||
Mode::from_bool(is_dark_mode_enabled())
|
||||
}
|
2
desktop/tauri/rust-dark-light/src/platforms/macos/mod.rs
Normal file
2
desktop/tauri/rust-dark-light/src/platforms/macos/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod detect;
|
||||
pub mod notify;
|
23
desktop/tauri/rust-dark-light/src/platforms/macos/notify.rs
Normal file
23
desktop/tauri/rust-dark-light/src/platforms/macos/notify.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use std::task::Poll;
|
||||
|
||||
use futures::{stream, Stream};
|
||||
|
||||
use crate::{detect, Mode};
|
||||
|
||||
pub async fn subscribe() -> anyhow::Result<impl Stream<Item = Mode> + Send> {
|
||||
let mut last_mode = detect();
|
||||
|
||||
let stream = stream::poll_fn(move |ctx| -> Poll<Option<Mode>> {
|
||||
let current_mode = detect();
|
||||
|
||||
if current_mode != last_mode {
|
||||
last_mode = current_mode;
|
||||
Poll::Ready(Some(current_mode))
|
||||
} else {
|
||||
ctx.waker().wake_by_ref();
|
||||
Poll::Pending
|
||||
}
|
||||
});
|
||||
|
||||
Ok(stream)
|
||||
}
|
48
desktop/tauri/rust-dark-light/src/platforms/mod.rs
Normal file
48
desktop/tauri/rust-dark-light/src/platforms/mod.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
#[cfg(target_os = "macos")]
|
||||
pub mod macos;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub use macos as platform;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub mod windows;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows as platform;
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
pub mod freedesktop;
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
pub use freedesktop as platform;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub mod websys;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub use websys as platform;
|
||||
|
||||
#[cfg(not(any(
|
||||
target_os = "macos",
|
||||
target_os = "windows",
|
||||
target_os = "linux",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_arch = "wasm32"
|
||||
)))]
|
||||
pub mod platform {
|
||||
pub fn detect() -> crate::Mode {
|
||||
super::Mode::Light
|
||||
}
|
||||
}
|
11
desktop/tauri/rust-dark-light/src/platforms/websys/detect.rs
Normal file
11
desktop/tauri/rust-dark-light/src/platforms/websys/detect.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
use crate::Mode;
|
||||
|
||||
pub fn detect() -> crate::Mode {
|
||||
if let Some(window) = web_sys::window() {
|
||||
let query_result = window.match_media("(prefers-color-scheme: dark)");
|
||||
if let Ok(Some(mql)) = query_result {
|
||||
return Mode::from_bool(mql.matches());
|
||||
}
|
||||
}
|
||||
Mode::Light
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
pub mod detect;
|
||||
pub mod notify;
|
23
desktop/tauri/rust-dark-light/src/platforms/websys/notify.rs
Normal file
23
desktop/tauri/rust-dark-light/src/platforms/websys/notify.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use std::task::Poll;
|
||||
|
||||
use futures::{stream, Stream};
|
||||
|
||||
use crate::{detect, Mode};
|
||||
|
||||
pub async fn subscribe() -> anyhow::Result<impl Stream<Item = Mode> + Send> {
|
||||
let mut last_mode = detect();
|
||||
|
||||
let stream = stream::poll_fn(move |ctx| -> Poll<Option<Mode>> {
|
||||
let current_mode = detect();
|
||||
|
||||
if current_mode != last_mode {
|
||||
last_mode = current_mode;
|
||||
Poll::Ready(Some(current_mode))
|
||||
} else {
|
||||
ctx.waker().wake_by_ref();
|
||||
Poll::Pending
|
||||
}
|
||||
});
|
||||
|
||||
Ok(stream)
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
use crate::Mode;
|
||||
use winreg::RegKey;
|
||||
|
||||
const SUBKEY: &str = "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
|
||||
const VALUE: &str = "AppsUseLightTheme";
|
||||
|
||||
pub fn detect() -> Mode {
|
||||
let hkcu = RegKey::predef(winreg::enums::HKEY_CURRENT_USER);
|
||||
if let Ok(subkey) = hkcu.open_subkey(SUBKEY) {
|
||||
if let Ok(dword) = subkey.get_value::<u32, _>(VALUE) {
|
||||
return Mode::from_bool(dword == 0);
|
||||
}
|
||||
}
|
||||
Mode::Light
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
pub mod detect;
|
||||
pub mod notify;
|
|
@ -0,0 +1,23 @@
|
|||
use std::task::Poll;
|
||||
|
||||
use futures::{stream, Stream};
|
||||
|
||||
use crate::{detect, Mode};
|
||||
|
||||
pub async fn subscribe() -> anyhow::Result<impl Stream<Item = Mode> + Send> {
|
||||
let mut last_mode = detect();
|
||||
|
||||
let stream = stream::poll_fn(move |ctx| -> Poll<Option<Mode>> {
|
||||
let current_mode = detect();
|
||||
|
||||
if current_mode != last_mode {
|
||||
last_mode = current_mode;
|
||||
Poll::Ready(Some(current_mode))
|
||||
} else {
|
||||
ctx.waker().wake_by_ref();
|
||||
Poll::Pending
|
||||
}
|
||||
});
|
||||
|
||||
Ok(stream)
|
||||
}
|
1
desktop/tauri/rust-dark-light/src/utils/mod.rs
Normal file
1
desktop/tauri/rust-dark-light/src/utils/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod rgb;
|
23
desktop/tauri/rust-dark-light/src/utils/rgb.rs
Normal file
23
desktop/tauri/rust-dark-light/src/utils/rgb.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
/// Struct representing an RGB color
|
||||
pub(crate) struct Rgb(pub(crate) u32, pub(crate) u32, pub(crate) u32);
|
||||
|
||||
impl FromStr for Rgb {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let rgb = s
|
||||
.split(',')
|
||||
.map(|s| s.parse::<u32>().unwrap_or(255))
|
||||
.try_fold(vec![], |mut acc, x| {
|
||||
if acc.len() < 3 {
|
||||
acc.push(x);
|
||||
Ok(acc)
|
||||
} else {
|
||||
Err(anyhow::anyhow!("RGB format is invalid"))
|
||||
}
|
||||
})?;
|
||||
Ok(Rgb(rgb[0], rgb[1], rgb[2]))
|
||||
}
|
||||
}
|
6827
desktop/tauri/src-tauri/Cargo.lock
generated
6827
desktop/tauri/src-tauri/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "portmaster"
|
||||
version = "0.1.0"
|
||||
version = "2.0.0"
|
||||
description = "Portmaster UI"
|
||||
authors = ["Safing"]
|
||||
license = ""
|
||||
|
@ -12,21 +12,20 @@ rust-version = "1.64"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2.0.3", features = [] }
|
||||
tauri-build = { version = "2.0.5", features = [] }
|
||||
|
||||
[dependencies]
|
||||
# Tauri
|
||||
tauri = { version = "2.1.1", features = ["tray-icon", "image-png", "config-json5", "devtools"] }
|
||||
tauri-plugin-shell = "2.0.2"
|
||||
tauri-plugin-dialog = "2.0.3"
|
||||
tauri-plugin-clipboard-manager = "2.0.2"
|
||||
tauri-plugin-os = "2.0.1"
|
||||
tauri-plugin-single-instance = "2.0.1"
|
||||
tauri-plugin-notification = "2.0.1"
|
||||
tauri-plugin-log = "2.0.2"
|
||||
tauri-plugin-window-state = "2.0.2"
|
||||
tauri = { version = "2.2.5", features = ["tray-icon", "image-png", "config-json5", "devtools"] }
|
||||
tauri-plugin-shell = "2.2.0"
|
||||
tauri-plugin-dialog = "2.2.0"
|
||||
tauri-plugin-clipboard-manager = "2.1.11"
|
||||
tauri-plugin-os = "2.2.0"
|
||||
tauri-plugin-single-instance = "2.2.1"
|
||||
tauri-plugin-notification = "2.2.1"
|
||||
tauri-plugin-log = "2.2.1"
|
||||
tauri-plugin-window-state = "2.2.1"
|
||||
|
||||
tauri-cli = "2.1.0"
|
||||
clap_lex = "0.7.2"
|
||||
|
||||
# General
|
||||
|
@ -53,7 +52,7 @@ reqwest = { version = "0.12" }
|
|||
rfd = { version = "*", default-features = false, features = [ "tokio", "gtk3", "common-controls-v6" ] }
|
||||
open = "5.1.3"
|
||||
|
||||
dark-light = { git = "https://github.com/vlabo/rust-dark-light", rev = "1f955c84d0ea05729bb5ecab29fb1b315b9897de" }
|
||||
dark-light = { path = "../rust-dark-light" }
|
||||
|
||||
# Linux only
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# Update Tauri guide
|
||||
|
||||
Check latest versions of tauri packages and update them accordingly:
|
||||
Check latest versions of tauri packages and update them accordingly (https://crates.io/)
|
||||
Cargo.toml:
|
||||
```toml
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2.0.0-beta.19", features = [] } # Update to latest
|
||||
|
@ -21,21 +22,25 @@ tauri-plugin-window-state = "2.0.0-beta"
|
|||
tauri-cli = "2.0.0-beta.21" # Update to latest
|
||||
```
|
||||
|
||||
> The plugins will be auto updated based on tauri version.
|
||||
|
||||
Run:
|
||||
```sh
|
||||
cargo update
|
||||
```
|
||||
|
||||
Update WIX installer template:
|
||||
1. Get the latests [main.wxs](https://github.com/tauri-apps/tauri/blob/dev/tooling/bundler/src/bundle/windows/templates/main.wxs) template from the repository.
|
||||
2. Replace the contents of `templates/main_original.wxs` with the repository version.
|
||||
3. Replace the contents of `templates/main.wsx` and add the fallowing lines at the end of the file, inside the `Product` tag.
|
||||
> Make sure to update the npm tauri plugin dependencies to have the same version as the rust plugins. (desktop/angular)
|
||||
|
||||
## Update WIX installer template
|
||||
|
||||
> If the migration functionality is not needed anymore remove the template, this will cause tauri to use its default template and not call the migration script.
|
||||
|
||||
1. Get the latest [main.wxs](https://github.com/tauri-apps/tauri/blob/dev/tooling/bundler/src/bundle/windows/templates/main.wxs) template from the repository.
|
||||
2. Replace the contents of `templates/wix/main_original.wxs` with the repository version. (The file is kept only for reference)
|
||||
3. Replace the contents of `templates/wix/main.wsx` and add the fallowing lines at the end of the file, inside the `Product` tag.
|
||||
```xml
|
||||
<!-- Service fragments -->
|
||||
<CustomActionRef Id='InstallPortmasterService' />
|
||||
<CustomActionRef Id='StopPortmasterService' />
|
||||
<CustomActionRef Id='DeletePortmasterService' />
|
||||
<CustomActionRef Id='MigrationPropertySet' />
|
||||
<CustomActionRef Id='Migration' />
|
||||
<!-- Uncommenting the next line will cause the installer to check if the old service is running and fail. Without it, it will automatically stop and remove the old service without notifying the user. -->
|
||||
<!-- <CustomActionRef Id='CheckServiceStatus' /> -->
|
||||
<!-- End Service fragments -->
|
||||
```
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1100,6 +1100,11 @@
|
|||
"type": "string",
|
||||
"const": "core:webview:allow-reparent"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_webview_background_color command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:webview:allow-set-webview-background-color"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_webview_focus command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
@ -1180,6 +1185,11 @@
|
|||
"type": "string",
|
||||
"const": "core:webview:deny-reparent"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_webview_background_color command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:webview:deny-set-webview-background-color"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_webview_focus command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
@ -1395,6 +1405,21 @@
|
|||
"type": "string",
|
||||
"const": "core:window:allow-set-always-on-top"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_background_color command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:allow-set-background-color"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_badge_count command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:allow-set-badge-count"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_badge_label command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:allow-set-badge-label"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_closable command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
@ -1480,6 +1505,11 @@
|
|||
"type": "string",
|
||||
"const": "core:window:allow-set-minimizable"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_overlay_icon command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:allow-set-overlay-icon"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_position command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
@ -1740,6 +1770,21 @@
|
|||
"type": "string",
|
||||
"const": "core:window:deny-set-always-on-top"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_background_color command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:deny-set-background-color"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_badge_count command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:deny-set-badge-count"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_badge_label command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:deny-set-badge-label"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_closable command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
@ -1825,6 +1870,11 @@
|
|||
"type": "string",
|
||||
"const": "core:window:deny-set-minimizable"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_overlay_icon command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:deny-set-overlay-icon"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_position command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
|
|
@ -1100,6 +1100,11 @@
|
|||
"type": "string",
|
||||
"const": "core:webview:allow-reparent"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_webview_background_color command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:webview:allow-set-webview-background-color"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_webview_focus command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
@ -1180,6 +1185,11 @@
|
|||
"type": "string",
|
||||
"const": "core:webview:deny-reparent"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_webview_background_color command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:webview:deny-set-webview-background-color"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_webview_focus command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
@ -1395,6 +1405,21 @@
|
|||
"type": "string",
|
||||
"const": "core:window:allow-set-always-on-top"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_background_color command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:allow-set-background-color"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_badge_count command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:allow-set-badge-count"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_badge_label command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:allow-set-badge-label"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_closable command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
@ -1480,6 +1505,11 @@
|
|||
"type": "string",
|
||||
"const": "core:window:allow-set-minimizable"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_overlay_icon command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:allow-set-overlay-icon"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_position command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
@ -1740,6 +1770,21 @@
|
|||
"type": "string",
|
||||
"const": "core:window:deny-set-always-on-top"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_background_color command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:deny-set-background-color"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_badge_count command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:deny-set-badge-count"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_badge_label command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:deny-set-badge-label"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_closable command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
@ -1825,6 +1870,11 @@
|
|||
"type": "string",
|
||||
"const": "core:window:deny-set-minimizable"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_overlay_icon command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:deny-set-overlay-icon"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_position command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
|
|
@ -1100,6 +1100,11 @@
|
|||
"type": "string",
|
||||
"const": "core:webview:allow-reparent"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_webview_background_color command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:webview:allow-set-webview-background-color"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_webview_focus command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
@ -1180,6 +1185,11 @@
|
|||
"type": "string",
|
||||
"const": "core:webview:deny-reparent"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_webview_background_color command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:webview:deny-set-webview-background-color"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_webview_focus command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
@ -1395,6 +1405,21 @@
|
|||
"type": "string",
|
||||
"const": "core:window:allow-set-always-on-top"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_background_color command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:allow-set-background-color"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_badge_count command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:allow-set-badge-count"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_badge_label command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:allow-set-badge-label"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_closable command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
@ -1480,6 +1505,11 @@
|
|||
"type": "string",
|
||||
"const": "core:window:allow-set-minimizable"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_overlay_icon command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:allow-set-overlay-icon"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_position command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
@ -1740,6 +1770,21 @@
|
|||
"type": "string",
|
||||
"const": "core:window:deny-set-always-on-top"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_background_color command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:deny-set-background-color"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_badge_count command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:deny-set-badge-count"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_badge_label command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:deny-set-badge-label"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_closable command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
@ -1825,6 +1870,11 @@
|
|||
"type": "string",
|
||||
"const": "core:window:deny-set-minimizable"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_overlay_icon command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "core:window:deny-set-overlay-icon"
|
||||
},
|
||||
{
|
||||
"description": "Denies the set_position command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
}
|
||||
},
|
||||
"productName": "Portmaster",
|
||||
"version": "0.1.0",
|
||||
"identifier": "io.safing.portmaster", // this is added as a property to the shortcut on windows (ApplicationUserModelID). Used for notifications.
|
||||
"app": {
|
||||
"withGlobalTauri": true,
|
||||
|
@ -55,7 +54,7 @@
|
|||
"linux": {
|
||||
"deb": {
|
||||
"depends": [
|
||||
"libayatana-appindicator3"
|
||||
"libayatana-appindicator3-1"
|
||||
],
|
||||
"desktopTemplate": "../../../packaging/linux/portmaster.desktop",
|
||||
"files": {
|
||||
|
@ -63,7 +62,6 @@
|
|||
"/usr/lib/systemd/system/portmaster.service": "../../../packaging/linux/portmaster.service",
|
||||
|
||||
// Binary files
|
||||
"/usr/lib/portmaster/index.json": "binary/index.json",
|
||||
"/usr/lib/portmaster/portmaster-core": "binary/portmaster-core",
|
||||
"/usr/lib/portmaster/portmaster.zip": "binary/portmaster.zip",
|
||||
"/usr/lib/portmaster/assets.zip": "binary/assets.zip",
|
||||
|
@ -77,6 +75,10 @@
|
|||
"/var/lib/portmaster/intel/intermediate.dsdl": "intel/intermediate.dsdl",
|
||||
"/var/lib/portmaster/intel/urgent.dsdl": "intel/urgent.dsdl",
|
||||
|
||||
"/var/lib/portmaster/intel/main-intel.yaml" : "intel/main-intel.yaml",
|
||||
"/var/lib/portmaster/intel/notifications.yaml": "intel/notifications.yaml",
|
||||
"/var/lib/portmaster/intel/news.yaml" : "intel/news.yaml",
|
||||
|
||||
// Shortcut
|
||||
"/etc/xdg/autostart/portmaster.desktop": "../../../packaging/linux/portmaster-autostart.desktop"
|
||||
},
|
||||
|
@ -94,7 +96,6 @@
|
|||
"/usr/lib/systemd/system/portmaster.service": "../../../packaging/linux/portmaster.service",
|
||||
|
||||
// Binary files
|
||||
"/usr/lib/portmaster/index.json": "binary/index.json",
|
||||
"/usr/lib/portmaster/portmaster-core": "binary/portmaster-core",
|
||||
"/usr/lib/portmaster/portmaster.zip": "binary/portmaster.zip",
|
||||
"/usr/lib/portmaster/assets.zip": "binary/assets.zip",
|
||||
|
@ -108,6 +109,10 @@
|
|||
"/var/lib/portmaster/intel/intermediate.dsdl": "intel/intermediate.dsdl",
|
||||
"/var/lib/portmaster/intel/urgent.dsdl": "intel/urgent.dsdl",
|
||||
|
||||
"/var/lib/portmaster/intel/main-intel.yaml" : "intel/main-intel.yaml",
|
||||
"/var/lib/portmaster/intel/notifications.yaml": "intel/notifications.yaml",
|
||||
"/var/lib/portmaster/intel/news.yaml" : "intel/news.yaml",
|
||||
|
||||
// Shortcut
|
||||
"/etc/xdg/autostart/portmaster.desktop": "../../../packaging/linux/portmaster-autostart.desktop"
|
||||
},
|
||||
|
@ -118,23 +123,23 @@
|
|||
"windows": {
|
||||
"nsis": {
|
||||
"installMode": "perMachine",
|
||||
"installerHooks": "templates/nsis_install_hooks.nsh",
|
||||
"installerHooks": "templates/nsis/install_hooks.nsh",
|
||||
"installerIcon": "../../../assets/data/icons/pm_light.ico"
|
||||
},
|
||||
"wix": {
|
||||
"fragmentPaths": [
|
||||
"templates/service.wxs",
|
||||
"templates/files.wxs"
|
||||
"templates/wix/files.wxs",
|
||||
"templates/wix/old_service_check.wxs",
|
||||
"templates/wix/migration.wxs",
|
||||
],
|
||||
"componentGroupRefs": ["BinaryAndIntelFiles"],
|
||||
"template": "templates/main.wxs"
|
||||
"template": "templates/wix/main.wxs"
|
||||
}
|
||||
},
|
||||
"targets": [
|
||||
"deb",
|
||||
"rpm",
|
||||
"nsis",
|
||||
"msi"
|
||||
"nsis" //, "msi"
|
||||
],
|
||||
"icon": [
|
||||
"../../../assets/data/icons/pm_dark_512.png",
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
SimpleSC - NSIS Service Control Plugin - License Agreement
|
||||
|
||||
This plugin is subject to the Mozilla Public License Version 1.1 (the "License");
|
||||
You may not use this plugin except in compliance with the License. You may
|
||||
obtain a copy of the License at http://www.mozilla.org/MPL.
|
||||
|
||||
Alternatively, you may redistribute this library, use and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published
|
||||
by the Free Software Foundation; either version 2.1 of the License,
|
||||
or (at your option) any later version. You may obtain a copy
|
||||
of the LGPL at www.gnu.org/copyleft.
|
||||
|
||||
Software distributed under the License is distributed on an "AS IS" basis,
|
||||
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
for the specific language governing rights and limitations under the License.
|
||||
|
||||
Copyright
|
||||
|
||||
Portions of this software are Copyright (C) 2001 - Peter Windridge, 2003 by
|
||||
Bernhard Mayer, Fixed and formatted by Brett Dever http://editor.nfscheats.com/
|
||||
|
||||
The original code is ServiceControl.pas, released April 16, 2007.
|
||||
|
||||
The initial developer of the original code is Rainer Budde (http://www.speed-soft.de).
|
||||
|
||||
SimpleSC - NSIS Service Control Plugin is written, published and maintaned by
|
||||
Rainer Budde (rainer@speed-soft.de).
|
|
@ -0,0 +1,335 @@
|
|||
NSIS Simple Service Plugin
|
||||
|
||||
This plugin contains basic service functions like start, stop the
|
||||
service or checking the service status. It also contains advanced
|
||||
service functions for example setting the service description, changed
|
||||
the logon account, granting or removing the service logon privilege.
|
||||
|
||||
|
||||
|
||||
|
||||
== Short Reference ==
|
||||
|
||||
|
||||
SimpleSC::InstallService [name_of_service] [display_name] [service_type] [start_type] [binary_path] [dependencies] [account] [password]
|
||||
SimpleSC::RemoveService [name_of_service]
|
||||
|
||||
SimpleSC::StartService [name_of_service] [arguments] [timeout]
|
||||
SimpleSC::StopService [name_of_service] [wait_for_file_release] [timeout]
|
||||
SimpleSC::PauseService [name_of_service] [timeout]
|
||||
SimpleSC::ContinueService [name_of_service] [timeout]
|
||||
SimpleSC::RestartService [name_of_service] [arguments] [timeout]
|
||||
SimpleSC::ExistsService [name_of_service]
|
||||
|
||||
SimpleSC::GetServiceDisplayName [name_of_service]
|
||||
SimpleSC::GetServiceName [display_name]
|
||||
SimpleSC::GetServiceStatus [name_of_service]
|
||||
SimpleSC::GetServiceDescription [name_of_service]
|
||||
SimpleSC::GetServiceStartType [name_of_service]
|
||||
SimpleSC::GetServiceBinaryPath [name_of_service]
|
||||
SimpleSC::GetServiceLogon [name_of_service]
|
||||
SimpleSC::GetServiceFailure [name_of_service]
|
||||
SimpleSC::GetServiceFailureFlag [name_of_service]
|
||||
SimpleSC::GetServiceDelayedAutoStartInfo [name_of_service]
|
||||
|
||||
SimpleSC::SetServiceDescription [name_of_service] [service_description]
|
||||
SimpleSC::SetServiceStartType [name_of_service] [start_type]
|
||||
SimpleSC::SetServiceBinaryPath [name_of_service] [binary_path]
|
||||
SimpleSC::SetServiceLogon [name_of_service] [account] [password]
|
||||
SimpleSC::SetServiceFailure [name_of_service] [reset_period] [reboot_message] [command] [action_type_1] [action_delay_1] [action_type_2] [action_delay_2] [action_type_3] [action_delay_3]
|
||||
SimpleSC::SetServiceFailureFlag [name_of_service] [failure_actions_on_non_crash_failures]
|
||||
SimpleSC::SetServiceDelayedAutoStartInfo [name_of_service] [delayed_autostart]
|
||||
|
||||
SimpleSC::GrantServiceLogonPrivilege [account]
|
||||
SimpleSC::RemoveServiceLogonPrivilege [account]
|
||||
|
||||
SimpleSC::ServiceIsPaused [name_of_service]
|
||||
SimpleSC::ServiceIsRunning [name_of_service]
|
||||
SimpleSC::ServiceIsStopped [name_of_service]
|
||||
|
||||
SimpleSC::GetErrorMessage [error_code]
|
||||
|
||||
|
||||
Parameters:
|
||||
|
||||
name_of_service - The name of the service used for Start/Stop commands and all further commands
|
||||
|
||||
display_name - The name as shown in the service control manager applet in system control
|
||||
|
||||
service_type - One of the following codes
|
||||
1 - SERVICE_KERNEL_DRIVER - Driver service.
|
||||
2 - SERVICE_FILE_SYSTEM_DRIVER - File system driver service.
|
||||
16 - SERVICE_WIN32_OWN_PROCESS - Service that runs in its own process. (Should be used in most cases)
|
||||
32 - SERVICE_WIN32_SHARE_PROCESS - Service that shares a process with one or more other services.
|
||||
256 - SERVICE_INTERACTIVE_PROCESS - The service can interact with the desktop.
|
||||
Note: If you specify either SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS,
|
||||
and the service is running in the context of the LocalSystem account,
|
||||
you can also specify this value.
|
||||
Example: SERVICE_WIN32_OWN_PROCESS or SERVICE_INTERACTIVE_PROCESS - (16 or 256) = 272
|
||||
Note: Services cannot directly interact with a user as of Windows Vista.
|
||||
Therefore, this technique should not be used in new code.
|
||||
See for more information: http://msdn2.microsoft.com/en-us/library/ms683502(VS.85).aspx
|
||||
|
||||
start_type - one of the following codes
|
||||
0 - SERVICE_BOOT_START - Driver boot stage start
|
||||
1 - SERVICE_SYSTEM_START - Driver scm stage start
|
||||
2 - SERVICE_AUTO_START - Service auto start (Should be used in most cases)
|
||||
3 - SERVICE_DEMAND_START - Driver/service manual start
|
||||
4 - SERVICE_DISABLED - Driver/service disabled
|
||||
|
||||
service_status - one of the following codes
|
||||
1 - SERVICE_STOPPED
|
||||
2 - SERVICE_START_PENDING
|
||||
3 - SERVICE_STOP_PENDING
|
||||
4 - SERVICE_RUNNING
|
||||
5 - SERVICE_CONTINUE_PENDING
|
||||
6 - SERVICE_PAUSE_PENDING
|
||||
7 - SERVICE_PAUSED
|
||||
|
||||
binary_path - The path to the binary including all necessary parameters
|
||||
|
||||
dependencies - Needed services, controls which services have to be started before this one; use the forward slash "/" to add more more than one service
|
||||
|
||||
account - The username/account which should be used
|
||||
|
||||
password - Password of the aforementioned account to be able to logon as a service
|
||||
Note: If you do not specify account/password, the local system account will be used to run the service
|
||||
|
||||
arguments - Arguments passed to the service main function.
|
||||
Note: Driver services do not receive these arguments.
|
||||
|
||||
reset_period - The time after which to reset the failure count to zero if there are no failures, in seconds. Specify 0 (INFINITE) to indicate that this value should never be reset
|
||||
|
||||
reboot_message - The message to be broadcast to server users before rebooting
|
||||
|
||||
command - The command line of the process to execute in response to the SC_ACTION_RUN_COMMAND service controller action. This process runs under the same account as the service
|
||||
|
||||
timeout - Timeout in seconds of the function
|
||||
|
||||
action_type_x - one of the following codes for the action to be performed
|
||||
0 - SC_ACTION_NONE - No action
|
||||
1 - SC_ACTION_RESTART - Restart the service
|
||||
2 - SC_ACTION_REBOOT - Reboot the computer (Note: The service user must have the SE_SHUTDOWN_NAME privilege)
|
||||
3 - SC_ACTION_RUN_COMMAND - Run a command
|
||||
|
||||
action_delay_x - The time to wait before performing the specified action, in milliseconds
|
||||
|
||||
failure_actions_on_non_crash_failures - This setting determines when failure actions are to be executed
|
||||
0 - The failure actions executed only if the service terminates without reporting a status of SERVICE_STOPPED
|
||||
1 - The failure actions executed if the status of a service is SERVICE_STOPPED but the exit code of the service is not 0
|
||||
|
||||
delayed_autostart - The delayed auto-start setting of an auto-start service
|
||||
0 - The service will be started during system boot.
|
||||
1 - The service will be started after other auto-start services are started plus a short delay
|
||||
|
||||
error_code - Error code of a function
|
||||
|
||||
service_description - The description as shown in the service control manager applet in system control
|
||||
|
||||
wait_for_file_release - Wait for file release after the service is stopped. This is useful if the binary file will be overwritten after stopping the service.
|
||||
0 - NO_WAIT - No wait for file release
|
||||
1 - WAIT - Wait for file release
|
||||
Note: If SERVICE_WIN32_OWN_PROCESS is used this option should be set to WAIT.
|
||||
If SERVICE_WIN32_SHARE_PROCESS is used this option should only be set to WAIT if the last service
|
||||
in the process is stopped.
|
||||
|
||||
|
||||
|
||||
|
||||
== The Sample Script ==
|
||||
|
||||
|
||||
; Install a service - ServiceType own process - StartType automatic - NoDependencies - Logon as System Account
|
||||
SimpleSC::InstallService "MyService" "My Service Display Name" "16" "2" "C:\MyPath\MyService.exe" "" "" ""
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Install a service - ServiceType interact with desktop - StartType automatic - Dependencies on "Windows Time Service" (w32time) and "WWW Publishing Service" (w3svc) - Logon as System Account
|
||||
SimpleSC::InstallService "MyService" "My Service Display Name" "272" "2" "C:\MyPath\MyService.exe" "w32time/w3svc" "" ""
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Remove a service
|
||||
SimpleSC::RemoveService "MyService"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Start a service
|
||||
SimpleSC::StartService "MyService" "" 30
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Start a service with two arguments "/param1=true" "/param2=1"
|
||||
SimpleSC::StartService "MyService" "/param1=true /param2=1" 30
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Start a service with two arguments "-p param1" "-param2"
|
||||
SimpleSC::StartService "MyService" '"-p param1" -param2' 30
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Stop a service and waits for file release
|
||||
SimpleSC::StopService "MyService" 1 30
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Stops two services and waits for file release after the last service is stopped
|
||||
SimpleSC::StopService "MyService1" 0 30
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
SimpleSC::StopService "MyService2" 1 30
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Pause a service
|
||||
SimpleSC::PauseService "MyService" 30
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Continue a service
|
||||
SimpleSC::ContinueService "MyService" 30
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Restart a service
|
||||
SimpleSC::RestartService "MyService" "" 30
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Restart a service with two arguments "/param1=true" "/param2=1"
|
||||
SimpleSC::RestartService "MyService" "/param1=true /param2=1" 30
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Start a service with two arguments "-p param1" "-param2"
|
||||
SimpleSC::RestartService "MyService" '"-p param1" -param2' 30
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Check if the service exists
|
||||
SimpleSC::ExistsService "MyService"
|
||||
Pop $0 ; returns an errorcode if the service doesn´t exists (<>0)/service exists (0)
|
||||
|
||||
; Get the displayname of a service
|
||||
SimpleSC::GetServiceDisplayName "MyService"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Pop $1 ; returns the displayname of the service
|
||||
|
||||
; Get the servicename of a service by the displayname
|
||||
SimpleSC::GetServiceName "MyService"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Pop $1 ; returns the servicename of the service
|
||||
|
||||
; Get the current status of a service
|
||||
SimpleSC::GetServiceStatus "MyService"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Pop $1 ; return the status of the service (See "service_status" in the parameters)
|
||||
|
||||
; Get the description of a service
|
||||
SimpleSC::GetServiceDescription "MyService"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Pop $1 ; returns the description of the service
|
||||
|
||||
; Get the start type of the service
|
||||
SimpleSC::GetServiceStartType "MyService"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Pop $1 ; returns the start type of the service (see "start_type" in the parameters)
|
||||
|
||||
; Get the binary path of a service
|
||||
SimpleSC::GetServiceBinaryPath "MyService"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Pop $1 ; returns the binary path of the service
|
||||
|
||||
; Get the logon user of the service
|
||||
SimpleSC::GetServiceLogon "MyService"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Pop $1 ; returns the logon username of the service
|
||||
|
||||
; Get the failure configuration of a service
|
||||
SimpleSC::GetServiceFailure "MyService"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Pop $1 ; returns the reset period
|
||||
Pop $2 ; returns the reboot message
|
||||
Pop $3 ; returns the command
|
||||
Pop $4 ; returns the first action (See "action_type_x" in the parameters)
|
||||
Pop $5 ; returns the first action delay
|
||||
Pop $6 ; returns the second action (See "action_type_x" in the parameters)
|
||||
Pop $7 ; returns the second action delay
|
||||
Pop $8 ; returns the third action (See "action_type_x" in the parameters)
|
||||
Pop $9 ; returns the third action delay
|
||||
|
||||
; Get the failure flag configuration of a service
|
||||
SimpleSC::GetServiceFailureFlag "MyService"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Pop $1 ; returns the service flag
|
||||
|
||||
; Get the delayed auto-start configuration of a service
|
||||
SimpleSC::GetServiceDelayedAutoStartInfo "MyService"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Pop $1 ; returns the delayed auto-start configuration
|
||||
|
||||
; Set the description of a service
|
||||
SimpleSC::SetServiceDescription "MyService" "Sample Description"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Set the starttype to automatic of a service
|
||||
SimpleSC::SetServiceStartType "MyService" "2"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Sets the service binary path
|
||||
SimpleSC::SetServiceBinaryPath "MyService" "C:\MySoftware\MyService.exe"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Sets the service logon to a user and grant the user the "SeServiceLogonPrivilege"
|
||||
SimpleSC::SetServiceLogon "MyService" "MyServiceUser" "MyServiceUserPassword"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
IntCmp $0 0 +1 Done Done ; If successful grant the service logon privilege to "MyServiceUser"
|
||||
; Note: Every serviceuser must have the ServiceLogonPrivilege to start the service
|
||||
SimpleSC::GrantServiceLogonPrivilege "MyServiceUser"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Done:
|
||||
|
||||
; Sets the service failure configuration - First action: Restart the service after one minute - Second action: Reboot the computer after five minutes
|
||||
SimpleSC::SetServiceFailure "MyService" "0" "" "" "1" "60000" "2" "300000" "0" "0"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Sets the failure flag configuration of a service
|
||||
SimpleSC::SetServiceFailureFlag "MyService" "1"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Sets the delayed auto-start configuration of a service
|
||||
SimpleSC::SetServiceDelayedAutoStartInfo "MyService" "1"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Remove the "SeServiceLogonPrivilege" from a user
|
||||
SimpleSC::RemoveServiceLogonPrivilege "MyServiceUser"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
|
||||
; Check if the service is paused
|
||||
SimpleSC::ServiceIsPaused "MyService"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Pop $1 ; returns 1 (service is paused) - returns 0 (service is not paused)
|
||||
|
||||
; Check if the service is running
|
||||
SimpleSC::ServiceIsRunning "MyService"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Pop $1 ; returns 1 (service is running) - returns 0 (service is not running)
|
||||
|
||||
; Check if the service is stopped
|
||||
SimpleSC::ServiceIsStopped "MyService"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Pop $1 ; returns 1 (service is stopped) - returns 0 (service is not stopped)
|
||||
|
||||
; Show the error message if a function fails
|
||||
SimpleSC::StopService "MyService" 1 30
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
IntCmp $0 0 Done +1 +1
|
||||
Push $0
|
||||
SimpleSC::GetErrorMessage
|
||||
Pop $0
|
||||
MessageBox MB_OK|MB_ICONSTOP "Stopping fails - Reason: $0"
|
||||
Done:
|
||||
|
||||
|
||||
|
||||
|
||||
== Important Notes ==
|
||||
- The function "SetServiceLogon" only works if the servicetype is
|
||||
"SERVICE_WIN32_OWN_PROCESS".
|
||||
- The functions "GetServiceDescription", "SetServiceDescription", "GetServiceFailure" and
|
||||
"SetServiceFailure" are only available on systems higher than Windows NT.
|
||||
- The function "GetServiceFailureFlag", "SetServiceFailureFlag", "GetServiceDelayedAutoStartInfo" and
|
||||
"SetServiceDelayedAutoStartInfo" are only available on systems higher than Windows 2003.
|
||||
- If you change the logon of an service to a new user you have to grant him
|
||||
the Service Logon Privilege. Otherwise the service cannot be started by
|
||||
the user you have assigned.
|
||||
- The functions StartService, StopService, PauseService and ContinueService uses
|
||||
a timeout of 30 seconds. This means the function must be executed within 30 seconds,
|
||||
otherwise the functions will return an error.
|
Binary file not shown.
|
@ -0,0 +1,259 @@
|
|||
{
|
||||
License Agreement
|
||||
|
||||
This content is subject to the Mozilla Public License Version 1.1 (the "License");
|
||||
You may not use this plugin except in compliance with the License. You may
|
||||
obtain a copy of the License at http://www.mozilla.org/MPL.
|
||||
|
||||
Alternatively, you may redistribute this library, use and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published
|
||||
by the Free Software Foundation; either version 2.1 of the License,
|
||||
or (at your option) any later version. You may obtain a copy
|
||||
of the LGPL at www.gnu.org/copyleft.
|
||||
|
||||
Software distributed under the License is distributed on an "AS IS" basis,
|
||||
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
for the specific language governing rights and limitations under the License.
|
||||
|
||||
The original code is LSASecurityControl.pas, released April 16, 2007.
|
||||
|
||||
The initial developer of the original code is Rainer Döpke
|
||||
(Formerly: Rainer Budde) (https://www.speed-soft.de).
|
||||
|
||||
SimpleSC - NSIS Service Control Plugin is written, published and maintained by
|
||||
Rainer Döpke (rainer@speed-soft.de).
|
||||
}
|
||||
unit LSASecurityControl;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Winapi.Windows;
|
||||
|
||||
function GrantPrivilege(AccountName: String; PrivilegeName: String): Integer;
|
||||
function RemovePrivilege(AccountName: String; PrivilegeName: String): Integer;
|
||||
function EnablePrivilege(PrivilegeName: String): Integer;
|
||||
function DisablePrivilege(PrivilegeName: String): Integer;
|
||||
|
||||
implementation
|
||||
|
||||
type
|
||||
LSA_HANDLE = Pointer;
|
||||
TLSAHandle = LSA_HANDLE;
|
||||
|
||||
LSA_UNICODE_STRING = record
|
||||
Length: Word;
|
||||
MaximumLength: Word;
|
||||
Buffer: PWideChar;
|
||||
end;
|
||||
TLSAUnicodeString = LSA_UNICODE_STRING;
|
||||
PLSAUnicodeString = ^TLSAUnicodeString;
|
||||
|
||||
LSA_OBJECT_ATTRIBUTES = record
|
||||
Length: ULONG;
|
||||
RootDirectory: THandle;
|
||||
ObjectName: PLSAUnicodeString;
|
||||
Attributes: ULONG;
|
||||
SecurityDescriptor: Pointer;
|
||||
SecurityQualityOfService: Pointer;
|
||||
end;
|
||||
TLsaObjectAttributes = LSA_OBJECT_ATTRIBUTES;
|
||||
PLsaObjectAttributes = ^TLsaObjectAttributes;
|
||||
|
||||
function LsaOpenPolicy(SystemName: PLSAUnicodeString; var ObjectAttributes: TLsaObjectAttributes; DesiredAccess: ACCESS_MASK; var PolicyHandle: LSA_HANDLE): DWORD; stdcall; external 'advapi32.dll';
|
||||
function LsaAddAccountRights(PolicyHandle: LSA_HANDLE; AccountSid: PSID; UserRights: PLSAUnicodeString; CountOfRights: ULONG): DWORD; stdcall; external 'advapi32.dll';
|
||||
function LsaRemoveAccountRights(PolicyHandle: LSA_HANDLE; AccountSid: PSID; AllRights: Boolean; UserRights: PLSAUnicodeString; CountOfRights: ULONG): DWORD; stdcall; external 'advapi32.dll';
|
||||
function LsaClose(ObjectHandle: LSA_HANDLE): DWORD; stdcall; external 'advapi32.dll';
|
||||
|
||||
|
||||
function GetAccountSid(const AccountName: String; var Sid: PSID): Integer;
|
||||
var
|
||||
DomainSize: LongWord;
|
||||
SidSize: LongWord;
|
||||
Domain: String;
|
||||
Use: SID_NAME_USE;
|
||||
begin
|
||||
Result := 0;
|
||||
|
||||
SidSize := 0;
|
||||
DomainSize := 0;
|
||||
|
||||
if not LookupAccountName(nil, PChar(AccountName), nil, SidSize, nil, DomainSize, Use) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then
|
||||
begin
|
||||
SetLength(Domain, DomainSize);
|
||||
Sid := AllocMem(SidSize);
|
||||
|
||||
if not LookupAccountName(nil, PChar(AccountName), Sid, SidSize, PChar(Domain), DomainSize, Use) then
|
||||
begin
|
||||
Result := GetLastError;
|
||||
FreeMem(Sid);
|
||||
Sid := nil;
|
||||
end;
|
||||
end
|
||||
else
|
||||
Result := GetLastError;
|
||||
end;
|
||||
|
||||
function GrantPrivilege(AccountName: String; PrivilegeName: String): Integer;
|
||||
const
|
||||
UNICODE_NULL = WCHAR(0);
|
||||
POLICY_CREATE_ACCOUNT = $00000010;
|
||||
POLICY_LOOKUP_NAMES = $00000800;
|
||||
var
|
||||
SID: PSID;
|
||||
PolicyHandle: TLSAHandle;
|
||||
LSAPrivilegeName: TLSAUnicodeString;
|
||||
LSAObjectAttributes: TLsaObjectAttributes;
|
||||
pwszPrivilegeName: PWideChar;
|
||||
PrivilegeNameLength: Cardinal;
|
||||
Status: DWORD;
|
||||
begin
|
||||
Result := 0;
|
||||
|
||||
GetMem(pwszPrivilegeName, Length(PrivilegeName) * SizeOf(WideChar) + 1);
|
||||
StringToWideChar(PrivilegeName, pwszPrivilegeName, Length(PrivilegeName) * SizeOf(WideChar) + 1);
|
||||
ZeroMemory(@LSAObjectAttributes, SizeOf(TLsaObjectAttributes));
|
||||
PrivilegeNameLength := Length(pwszPrivilegeName);
|
||||
|
||||
if PrivilegeNameLength > 0 then
|
||||
begin
|
||||
Result := GetAccountSid(AccountName, SID);
|
||||
|
||||
if Result = 0 then
|
||||
begin
|
||||
LSAPrivilegeName.Length := PrivilegeNameLength * SizeOf(WideChar);
|
||||
LSAPrivilegeName.MaximumLength := LSAPrivilegeName.Length + SizeOf(UNICODE_NULL);
|
||||
LSAPrivilegeName.Buffer := pwszPrivilegeName;
|
||||
|
||||
Status := LsaOpenPolicy(nil, LSAObjectAttributes, POLICY_LOOKUP_NAMES or POLICY_CREATE_ACCOUNT, PolicyHandle);
|
||||
try
|
||||
if Status = 0 then
|
||||
Result := LsaAddAccountRights(PolicyHandle, Sid, @LSAPrivilegeName, 1)
|
||||
else
|
||||
Result := Status;
|
||||
finally
|
||||
LsaClose(PolicyHandle);
|
||||
end;
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
FreeMem(pwszPrivilegeName);
|
||||
end;
|
||||
|
||||
function RemovePrivilege(AccountName: String; PrivilegeName: String): Integer;
|
||||
const
|
||||
UNICODE_NULL = WCHAR(0);
|
||||
POLICY_CREATE_ACCOUNT = $00000010;
|
||||
POLICY_LOOKUP_NAMES = $00000800;
|
||||
var
|
||||
SID: PSID;
|
||||
PolicyHandle: TLSAHandle;
|
||||
LSAPrivilegeName: TLSAUnicodeString;
|
||||
LSAObjectAttributes: TLsaObjectAttributes;
|
||||
pwszPrivilegeName: PWideChar;
|
||||
PrivilegeNameLength: Cardinal;
|
||||
Status: DWORD;
|
||||
begin
|
||||
Result := 0;
|
||||
|
||||
GetMem(pwszPrivilegeName, Length(PrivilegeName) * SizeOf(WideChar) + 1);
|
||||
StringToWideChar(PrivilegeName, pwszPrivilegeName, Length(PrivilegeName) * SizeOf(WideChar) + 1);
|
||||
ZeroMemory(@LSAObjectAttributes, SizeOf(TLsaObjectAttributes));
|
||||
PrivilegeNameLength := Length(pwszPrivilegeName);
|
||||
|
||||
if PrivilegeNameLength > 0 then
|
||||
begin
|
||||
Result := GetAccountSid(AccountName, SID);
|
||||
|
||||
if Result = 0 then
|
||||
begin
|
||||
LSAPrivilegeName.Length := PrivilegeNameLength * SizeOf(WideChar);
|
||||
LSAPrivilegeName.MaximumLength := LSAPrivilegeName.Length + SizeOf(UNICODE_NULL);
|
||||
LSAPrivilegeName.Buffer := pwszPrivilegeName;
|
||||
|
||||
Status := LsaOpenPolicy(nil, LSAObjectAttributes, POLICY_LOOKUP_NAMES or POLICY_CREATE_ACCOUNT, PolicyHandle);
|
||||
|
||||
try
|
||||
if Status = 0 then
|
||||
Result := LsaRemoveAccountRights(PolicyHandle, Sid, False, @LSAPrivilegeName, 1)
|
||||
else
|
||||
Result := Status;
|
||||
finally
|
||||
LsaClose(PolicyHandle);
|
||||
end;
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
FreeMem(pwszPrivilegeName);
|
||||
end;
|
||||
|
||||
function EnablePrivilege(PrivilegeName: String): Integer;
|
||||
var
|
||||
TokenHandle: THandle;
|
||||
TokenPrivileges: TOKEN_PRIVILEGES;
|
||||
PreviousState: TOKEN_PRIVILEGES;
|
||||
ReturnLength: Cardinal;
|
||||
begin
|
||||
Result := 0;
|
||||
|
||||
if OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, TokenHandle) then
|
||||
begin
|
||||
try
|
||||
|
||||
if LookupPrivilegeValue(nil, PWideChar(PrivilegeName), TokenPrivileges.Privileges[0].Luid) then
|
||||
begin
|
||||
TokenPrivileges.PrivilegeCount := 1;
|
||||
TokenPrivileges.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
|
||||
|
||||
if not AdjustTokenPrivileges(TokenHandle, False, TokenPrivileges, SizeOf(TokenPrivileges), PreviousState, ReturnLength) then
|
||||
Result := System.GetLastError;
|
||||
end
|
||||
else
|
||||
Result := System.GetLastError;
|
||||
|
||||
finally
|
||||
CloseHandle(TokenHandle);
|
||||
end;
|
||||
end
|
||||
else
|
||||
Result := System.GetLastError;
|
||||
|
||||
end;
|
||||
|
||||
function DisablePrivilege(PrivilegeName: String): Integer;
|
||||
var
|
||||
TokenHandle: THandle;
|
||||
TokenPrivileges: TOKEN_PRIVILEGES;
|
||||
PreviousState: TOKEN_PRIVILEGES;
|
||||
ReturnLength: Cardinal;
|
||||
begin
|
||||
|
||||
Result := 0;
|
||||
|
||||
if OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, TokenHandle) then
|
||||
begin
|
||||
try
|
||||
|
||||
if LookupPrivilegeValue(nil, PWideChar(PrivilegeName), TokenPrivileges.Privileges[0].Luid) then
|
||||
begin
|
||||
TokenPrivileges.PrivilegeCount := 1;
|
||||
TokenPrivileges.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
|
||||
|
||||
if not AdjustTokenPrivileges(TokenHandle, False, TokenPrivileges, SizeOf(TokenPrivileges), PreviousState, ReturnLength) then
|
||||
Result := System.GetLastError;
|
||||
end
|
||||
else
|
||||
Result := System.GetLastError;
|
||||
|
||||
finally
|
||||
CloseHandle(TokenHandle);
|
||||
end;
|
||||
end
|
||||
else
|
||||
Result := System.GetLastError;
|
||||
|
||||
end;
|
||||
|
||||
end.
|
|
@ -0,0 +1,36 @@
|
|||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{0AF40426-B62C-4F43-8B49-19A70AEA0832}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Projects Include="SimpleSC.dproj">
|
||||
<Dependencies/>
|
||||
</Projects>
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<Borland.Personality>Default.Personality.12</Borland.Personality>
|
||||
<Borland.ProjectType/>
|
||||
<BorlandProject>
|
||||
<Default.Personality/>
|
||||
</BorlandProject>
|
||||
</ProjectExtensions>
|
||||
<Target Name="SimpleSC">
|
||||
<MSBuild Projects="SimpleSC.dproj"/>
|
||||
</Target>
|
||||
<Target Name="SimpleSC:Clean">
|
||||
<MSBuild Projects="SimpleSC.dproj" Targets="Clean"/>
|
||||
</Target>
|
||||
<Target Name="SimpleSC:Make">
|
||||
<MSBuild Projects="SimpleSC.dproj" Targets="Make"/>
|
||||
</Target>
|
||||
<Target Name="Build">
|
||||
<CallTarget Targets="SimpleSC"/>
|
||||
</Target>
|
||||
<Target Name="Clean">
|
||||
<CallTarget Targets="SimpleSC:Clean"/>
|
||||
</Target>
|
||||
<Target Name="Make">
|
||||
<CallTarget Targets="SimpleSC:Make"/>
|
||||
</Target>
|
||||
<Import Project="$(BDS)\Bin\CodeGear.Group.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Group.Targets')"/>
|
||||
</Project>
|
|
@ -0,0 +1,209 @@
|
|||
{
|
||||
Original Code from
|
||||
(C) 2001 - Peter Windridge
|
||||
|
||||
Code in separate unit and some changes
|
||||
2003 by Bernhard Mayer
|
||||
|
||||
Fixed and formatted by Brett Dever
|
||||
http://editor.nfscheats.com/
|
||||
|
||||
simply include this unit in your plugin project and export
|
||||
functions as needed
|
||||
}
|
||||
|
||||
unit nsis;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Winapi.Windows, Winapi.CommCtrl, System.SysUtils;
|
||||
|
||||
type
|
||||
VarConstants = (
|
||||
INST_0, // $0
|
||||
INST_1, // $1
|
||||
INST_2, // $2
|
||||
INST_3, // $3
|
||||
INST_4, // $4
|
||||
INST_5, // $5
|
||||
INST_6, // $6
|
||||
INST_7, // $7
|
||||
INST_8, // $8
|
||||
INST_9, // $9
|
||||
INST_R0, // $R0
|
||||
INST_R1, // $R1
|
||||
INST_R2, // $R2
|
||||
INST_R3, // $R3
|
||||
INST_R4, // $R4
|
||||
INST_R5, // $R5
|
||||
INST_R6, // $R6
|
||||
INST_R7, // $R7
|
||||
INST_R8, // $R8
|
||||
INST_R9, // $R9
|
||||
INST_CMDLINE, // $CMDLINE
|
||||
INST_INSTDIR, // $INSTDIR
|
||||
INST_OUTDIR, // $OUTDIR
|
||||
INST_EXEDIR, // $EXEDIR
|
||||
INST_LANG, // $LANGUAGE
|
||||
__INST_LAST
|
||||
);
|
||||
TVariableList = INST_0..__INST_LAST;
|
||||
|
||||
type
|
||||
PluginCallbackMessages = (
|
||||
NSPIM_UNLOAD, // This is the last message a plugin gets, do final cleanup
|
||||
NSPIM_GUIUNLOAD // Called after .onGUIEnd
|
||||
);
|
||||
TNSPIM = NSPIM_UNLOAD..NSPIM_GUIUNLOAD;
|
||||
|
||||
//TPluginCallback = function (const NSPIM: Integer): Pointer; cdecl;
|
||||
|
||||
TExecuteCodeSegment = function (const funct_id: Integer; const parent: HWND): Integer; stdcall;
|
||||
Tvalidate_filename = procedure (const filename: PChar); stdcall;
|
||||
TRegisterPluginCallback = function (const DllInstance: HMODULE; const CallbackFunction: Pointer): Integer; stdcall;
|
||||
|
||||
pexec_flags_t = ^exec_flags_t;
|
||||
exec_flags_t = record
|
||||
autoclose: Integer;
|
||||
all_user_var: Integer;
|
||||
exec_error: Integer;
|
||||
abort: Integer;
|
||||
exec_reboot: Integer;
|
||||
reboot_called: Integer;
|
||||
XXX_cur_insttype: Integer;
|
||||
plugin_api_version: Integer;
|
||||
silent: Integer;
|
||||
instdir_error: Integer;
|
||||
rtl: Integer;
|
||||
errlvl: Integer;
|
||||
alter_reg_view: Integer;
|
||||
status_update: Integer;
|
||||
end;
|
||||
|
||||
pextrap_t = ^extrap_t;
|
||||
extrap_t = record
|
||||
exec_flags: Pointer; // exec_flags_t;
|
||||
exec_code_segment: TExecuteCodeSegment; // TFarProc;
|
||||
validate_filename: Pointer; // Tvalidate_filename;
|
||||
RegisterPluginCallback: Pointer; //TRegisterPluginCallback;
|
||||
end;
|
||||
|
||||
pstack_t = ^stack_t;
|
||||
stack_t = record
|
||||
next: pstack_t;
|
||||
text: PChar;
|
||||
end;
|
||||
|
||||
var
|
||||
g_stringsize: integer;
|
||||
g_stacktop: ^pstack_t;
|
||||
g_variables: PChar;
|
||||
g_hwndParent: HWND;
|
||||
g_hwndList: HWND;
|
||||
g_hwndLogList: HWND;
|
||||
g_extraparameters: pextrap_t;
|
||||
|
||||
procedure Init(const hwndParent: HWND; const string_size: integer; const variables: PChar; const stacktop: pointer; const extraparameters: pointer = nil);
|
||||
|
||||
function LogMessage(Msg : String): BOOL;
|
||||
function Call(NSIS_func : String) : Integer;
|
||||
function PopString(): string;
|
||||
procedure PushString(const str: string='');
|
||||
function GetUserVariable(const varnum: TVariableList): string;
|
||||
procedure SetUserVariable(const varnum: TVariableList; const value: string);
|
||||
procedure NSISDialog(const text, caption: string; const buttons: integer);
|
||||
|
||||
implementation
|
||||
|
||||
procedure Init(const hwndParent: HWND; const string_size: integer; const variables: PChar; const stacktop: pointer; const extraparameters: pointer = nil);
|
||||
begin
|
||||
g_stringsize := string_size;
|
||||
g_hwndParent := hwndParent;
|
||||
g_stacktop := stacktop;
|
||||
g_variables := variables;
|
||||
g_hwndList := FindWindowEx(FindWindowEx(g_hwndParent, 0, '#32770', nil), 0,'SysListView32', nil);
|
||||
g_extraparameters := extraparameters;
|
||||
end;
|
||||
|
||||
|
||||
function Call(NSIS_func : String) : Integer;
|
||||
var
|
||||
codeoffset: Integer; //The ID of nsis function
|
||||
begin
|
||||
Result := 0;
|
||||
codeoffset := StrToIntDef(NSIS_func, 0);
|
||||
if (codeoffset <> 0) and (g_extraparameters <> nil) then
|
||||
begin
|
||||
codeoffset := codeoffset - 1;
|
||||
Result := g_extraparameters.exec_code_segment(codeoffset, g_hwndParent);
|
||||
end;
|
||||
end;
|
||||
|
||||
function LogMessage(Msg : String): BOOL;
|
||||
var
|
||||
ItemCount : Integer;
|
||||
item: TLVItem;
|
||||
begin
|
||||
Result := FAlse;
|
||||
if g_hwndList = 0 then exit;
|
||||
FillChar( item, sizeof(item), 0 );
|
||||
ItemCount := SendMessage(g_hwndList, LVM_GETITEMCOUNT, 0, 0);
|
||||
item.iItem := ItemCount;
|
||||
item.mask := LVIF_TEXT;
|
||||
item.pszText := PChar(Msg);
|
||||
ListView_InsertItem(g_hwndList, item);
|
||||
ListView_EnsureVisible(g_hwndList, ItemCount, TRUE);
|
||||
end;
|
||||
|
||||
function PopString(): string;
|
||||
var
|
||||
th: pstack_t;
|
||||
begin
|
||||
if integer(g_stacktop^) <> 0 then begin
|
||||
th := g_stacktop^;
|
||||
Result := PChar(@th.text);
|
||||
g_stacktop^ := th.next;
|
||||
GlobalFree(HGLOBAL(th));
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure PushString(const str: string='');
|
||||
var
|
||||
th: pstack_t;
|
||||
begin
|
||||
if integer(g_stacktop) <> 0 then begin
|
||||
th := pstack_t(GlobalAlloc(GPTR, SizeOf(stack_t) + g_stringsize));
|
||||
lstrcpyn(@th.text, PChar(str), g_stringsize);
|
||||
th.next := g_stacktop^;
|
||||
g_stacktop^ := th;
|
||||
end;
|
||||
end;
|
||||
|
||||
function GetUserVariable(const varnum: TVariableList): string;
|
||||
begin
|
||||
if (integer(varnum) >= 0) and (integer(varnum) < integer(__INST_LAST)) then
|
||||
Result := g_variables + integer(varnum) * g_stringsize
|
||||
else
|
||||
Result := '';
|
||||
end;
|
||||
|
||||
procedure SetUserVariable(const varnum: TVariableList; const value: string);
|
||||
begin
|
||||
if (value <> '') and (integer(varnum) >= 0) and (integer(varnum) < integer(__INST_LAST)) then
|
||||
lstrcpy(g_variables + integer(varnum) * g_stringsize, PChar(value))
|
||||
end;
|
||||
|
||||
procedure NSISDialog(const text, caption: string; const buttons: integer);
|
||||
var
|
||||
hwndOwner: HWND;
|
||||
begin
|
||||
hwndOwner := g_hwndParent;
|
||||
if not IsWindow(g_hwndParent) then hwndOwner := 0; // g_hwndParent is not valid in NSPIM_[GUI]UNLOAD
|
||||
MessageBox(hwndOwner, PChar(text), PChar(caption), buttons);
|
||||
end;
|
||||
|
||||
begin
|
||||
|
||||
end.
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,609 @@
|
|||
library SimpleSC;
|
||||
|
||||
uses
|
||||
Winapi.Windows,
|
||||
System.SysUtils,
|
||||
NSIS in 'NSIS.pas',
|
||||
ServiceControl in 'ServiceControl.pas',
|
||||
LSASecurityControl in 'LSASecurityControl.pas';
|
||||
|
||||
function BoolToStr(Value: Boolean): String;
|
||||
begin
|
||||
if Value then
|
||||
Result := '1'
|
||||
else
|
||||
Result := '0';
|
||||
end;
|
||||
|
||||
function StrToBool(Value: String): Boolean;
|
||||
begin
|
||||
Result := Value = '1';
|
||||
end;
|
||||
|
||||
procedure InstallService(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
DisplayName: String;
|
||||
ServiceType: Cardinal;
|
||||
StartType: Cardinal;
|
||||
BinaryPath: String;
|
||||
Dependencies: String;
|
||||
Username: String;
|
||||
Password: String;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
DisplayName := PopString;
|
||||
ServiceType := StrToInt(PopString);
|
||||
StartType := StrToInt(PopString);
|
||||
BinaryPath := PopString;
|
||||
Dependencies := PopString;
|
||||
Username := PopString;
|
||||
Password := PopString;
|
||||
|
||||
ServiceResult := IntToStr(ServiceControl.InstallService(ServiceName, DisplayName, ServiceType, StartType, BinaryPath, Dependencies, Username, Password));
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure RemoveService(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
|
||||
ServiceResult := IntToStr(ServiceControl.RemoveService(ServiceName));
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure StartService(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
ServiceArguments: String;
|
||||
Timeout: Integer;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
ServiceArguments := PopString;
|
||||
Timeout := StrToInt(PopString);
|
||||
|
||||
ServiceResult := IntToStr(ServiceControl.StartService(ServiceName, ServiceArguments, Timeout));
|
||||
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure StopService(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
WaitForFileRelease: Boolean;
|
||||
Timeout: Integer;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
|
||||
WaitForFileRelease := StrToBool(PopString);
|
||||
Timeout := StrToInt(PopString);
|
||||
|
||||
ServiceResult := IntToStr(ServiceControl.StopService(ServiceName, WaitForFileRelease, Timeout));
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure PauseService(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
Timeout: Integer;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
Timeout := StrToInt(PopString);
|
||||
ServiceResult := IntToStr(ServiceControl.PauseService(ServiceName, Timeout));
|
||||
PushString(ServiceResult)
|
||||
end;
|
||||
|
||||
procedure ContinueService(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
Timeout: Integer;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
Timeout := StrToInt(PopString);
|
||||
ServiceResult := IntToStr(ServiceControl.ContinueService(ServiceName, Timeout));
|
||||
PushString(ServiceResult)
|
||||
end;
|
||||
|
||||
procedure GetServiceName(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
Var
|
||||
DisplayName: String;
|
||||
ServiceResult: String;
|
||||
ServiceName: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
DisplayName := PopString;
|
||||
ServiceResult := IntToStr(ServiceControl.GetServiceName(DisplayName, ServiceName));
|
||||
PushString(ServiceName);
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure GetServiceDisplayName(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
Var
|
||||
ServiceName: String;
|
||||
DisplayName: String;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
ServiceResult := IntToStr(ServiceControl.GetServiceDisplayName(ServiceName, DisplayName));
|
||||
PushString(DisplayName);
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure GetServiceStatus(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
Status: DWORD;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
ServiceResult := IntToStr(ServiceControl.GetServiceStatus(ServiceName, Status));
|
||||
PushString(IntToStr(Status));
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure GetServiceBinaryPath(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
BinaryPath: String;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
ServiceResult := IntToStr(ServiceControl.GetServiceBinaryPath(ServiceName, BinaryPath));
|
||||
PushString(BinaryPath);
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure GetServiceDescription(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
Description: String;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
ServiceResult := IntToStr(ServiceControl.GetServiceDescription(ServiceName, Description));
|
||||
PushString(Description);
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure GetServiceStartType(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
StartType: DWORD;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
ServiceResult := IntToStr(ServiceControl.GetServiceStartType(ServiceName, StartType));
|
||||
PushString(IntToStr(StartType));
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure GetServiceLogon(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
Username: String;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
ServiceResult := IntToStr(ServiceControl.GetServiceLogon(ServiceName, Username));
|
||||
PushString(Username);
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure GetServiceFailure(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
ResetPeriod: DWORD;
|
||||
RebootMessage: String;
|
||||
Command: String;
|
||||
Action1: Integer;
|
||||
ActionDelay1: DWORD;
|
||||
Action2: Integer;
|
||||
ActionDelay2: DWORD;
|
||||
Action3: Integer;
|
||||
ActionDelay3: DWORD;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
ServiceResult := IntToStr(ServiceControl.GetServiceFailure(ServiceName, ResetPeriod, RebootMessage, Command, Action1, ActionDelay1, Action2, ActionDelay2, Action3, ActionDelay3));
|
||||
PushString(IntToStr(ActionDelay3));
|
||||
PushString(IntToStr(Action3));
|
||||
PushString(IntToStr(ActionDelay2));
|
||||
PushString(IntToStr(Action2));
|
||||
PushString(IntToStr(ActionDelay1));
|
||||
PushString(IntToStr(Action1));
|
||||
PushString(Command);
|
||||
PushString(RebootMessage);
|
||||
PushString(IntToStr(ResetPeriod));
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure GetServiceFailureFlag(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
FailureActionsOnNonCrashFailures: Boolean;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
ServiceResult := IntToStr(ServiceControl.GetServiceFailureFlag(ServiceName, FailureActionsOnNonCrashFailures));
|
||||
PushString(BoolToStr(FailureActionsOnNonCrashFailures));
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure GetServiceDelayedAutoStartInfo(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
DelayedAutostart: Boolean;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
ServiceResult := IntToStr(ServiceControl.GetServiceDelayedAutoStartInfo(ServiceName, DelayedAutostart));
|
||||
PushString(BoolToStr(DelayedAutostart));
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure SetServiceDescription(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
Description: String;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
Description := PopString;
|
||||
ServiceResult := IntToStr(ServiceControl.SetServiceDescription(ServiceName, Description));
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure SetServiceStartType(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
ServiceStartType: DWORD;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
ServiceStartType := StrToInt(PopString);
|
||||
ServiceResult := IntToStr(ServiceControl.SetServiceStartType(ServiceName, ServiceStartType));
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure SetServiceLogon(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
Username: String;
|
||||
Password: String;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
Username := PopString;
|
||||
Password := PopString;
|
||||
|
||||
ServiceResult := IntToStr(ServiceControl.SetServiceLogon(ServiceName, Username, Password));
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure SetServiceBinaryPath(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
BinaryPath: String;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
BinaryPath := PopString;
|
||||
|
||||
ServiceResult := IntToStr(ServiceControl.SetServiceBinaryPath(ServiceName, BinaryPath));
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure SetServiceFailure(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
ResetPeriod: DWORD;
|
||||
RebootMessage: String;
|
||||
Command: String;
|
||||
Action1: Integer;
|
||||
ActionDelay1: DWORD;
|
||||
Action2: Integer;
|
||||
ActionDelay2: DWORD;
|
||||
Action3: Integer;
|
||||
ActionDelay3: DWORD;
|
||||
ServiceResult: Integer;
|
||||
PrivilegeResult: Integer;
|
||||
const
|
||||
SE_SHUTDOWN_PRIVILEGE = 'SeShutdownPrivilege';
|
||||
SC_ACTION_REBOOT = 2;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
ResetPeriod := StrToInt(PopString);
|
||||
RebootMessage := PopString;
|
||||
Command := PopString;
|
||||
Action1 := StrToInt(PopString);
|
||||
ActionDelay1 := StrToInt(PopString);
|
||||
Action2 := StrToInt(PopString);
|
||||
ActionDelay2 := StrToInt(PopString);
|
||||
Action3 := StrToInt(PopString);
|
||||
ActionDelay3 := StrToInt(PopString);
|
||||
|
||||
if (Action1 = SC_ACTION_REBOOT) or (Action2 = SC_ACTION_REBOOT) or (Action3 = SC_ACTION_REBOOT) then
|
||||
begin
|
||||
PrivilegeResult := LSASecurityControl.EnablePrivilege(SE_SHUTDOWN_PRIVILEGE);
|
||||
|
||||
if not PrivilegeResult = 0 then
|
||||
begin
|
||||
PushString(IntToStr(PrivilegeResult));
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
ServiceResult := ServiceControl.SetServiceFailure(ServiceName, ResetPeriod, RebootMessage, Command, Action1, ActionDelay1,
|
||||
Action2, ActionDelay2, Action3, ActionDelay3);
|
||||
|
||||
|
||||
if (Action1 = SC_ACTION_REBOOT) or (Action2 = SC_ACTION_REBOOT) or (Action3 = SC_ACTION_REBOOT) then
|
||||
begin
|
||||
PrivilegeResult := LSASecurityControl.DisablePrivilege(SE_SHUTDOWN_PRIVILEGE);
|
||||
|
||||
if not PrivilegeResult = 0 then
|
||||
begin
|
||||
PushString(IntToStr(PrivilegeResult));
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
PushString(IntToStr(ServiceResult));
|
||||
|
||||
end;
|
||||
|
||||
procedure SetServiceFailureFlag(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
FailureActionsOnNonCrashFailures: Boolean;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
FailureActionsOnNonCrashFailures := StrToBool(PopString);
|
||||
ServiceResult := IntToStr(ServiceControl.SetServiceFailureFlag(ServiceName, FailureActionsOnNonCrashFailures));
|
||||
PushString(ServiceResult)
|
||||
end;
|
||||
|
||||
procedure SetServiceDelayedAutoStartInfo(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
DelayedAutostart: Boolean;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
DelayedAutostart := StrToBool(PopString);
|
||||
ServiceResult := IntToStr(ServiceControl.SetServiceDelayedAutoStartInfo(ServiceName, DelayedAutostart));
|
||||
PushString(ServiceResult)
|
||||
end;
|
||||
|
||||
procedure ServiceIsRunning(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
IsRunning: Boolean;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
ServiceResult := IntToStr(ServiceControl.ServiceIsRunning(ServiceName, IsRunning));
|
||||
PushString(BoolToStr(IsRunning));
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure ServiceIsStopped(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
IsStopped: Boolean;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
ServiceResult := IntToStr(ServiceControl.ServiceIsStopped(ServiceName, IsStopped));
|
||||
PushString(BoolToStr(IsStopped));
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure ServiceIsPaused(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
IsPaused: Boolean;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
ServiceResult := IntToStr(ServiceControl.ServiceIsPaused(ServiceName, IsPaused));
|
||||
PushString(BoolToStr(IsPaused));
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure RestartService(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
ServiceArguments: String;
|
||||
Timeout: Integer;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
ServiceArguments := PopString;
|
||||
Timeout := StrToInt(PopString);
|
||||
ServiceResult := IntToStr(ServiceControl.RestartService(ServiceName, ServiceArguments, Timeout));
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure ExistsService(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ServiceName: String;
|
||||
ServiceResult: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ServiceName := PopString;
|
||||
|
||||
ServiceResult := IntToStr(ServiceControl.ExistsService(ServiceName));
|
||||
PushString(ServiceResult);
|
||||
end;
|
||||
|
||||
procedure GrantServiceLogonPrivilege(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
AccountName: String;
|
||||
LSAResult: String;
|
||||
const
|
||||
SE_SERVICE_LOGON_RIGHT = 'SeServiceLogonRight';
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
AccountName := PopString;
|
||||
|
||||
LSAResult := IntToStr(LSASecurityControl.GrantPrivilege(AccountName, SE_SERVICE_LOGON_RIGHT));
|
||||
PushString(LSAResult);
|
||||
end;
|
||||
|
||||
procedure RemoveServiceLogonPrivilege(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
AccountName: String;
|
||||
LSAResult: String;
|
||||
const
|
||||
SE_SERVICE_LOGON_RIGHT = 'SeServiceLogonRight';
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
AccountName := PopString;
|
||||
|
||||
LSAResult := IntToStr(LSASecurityControl.RemovePrivilege(AccountName, SE_SERVICE_LOGON_RIGHT));
|
||||
PushString(LSAResult);
|
||||
end;
|
||||
|
||||
procedure GetErrorMessage(const hwndParent: HWND; const string_size: integer;
|
||||
const variables: PChar; const stacktop: pointer); cdecl;
|
||||
var
|
||||
ErrorCode: Integer;
|
||||
ErrorMessage: String;
|
||||
begin
|
||||
Init(hwndParent, string_size, variables, stacktop);
|
||||
|
||||
ErrorCode := StrToInt(PopString);
|
||||
|
||||
ErrorMessage := ServiceControl.GetErrorMessage(ErrorCode);
|
||||
PushString(ErrorMessage);
|
||||
end;
|
||||
|
||||
exports InstallService;
|
||||
exports ExistsService;
|
||||
exports RemoveService;
|
||||
exports StartService;
|
||||
exports StopService;
|
||||
exports PauseService;
|
||||
exports ContinueService;
|
||||
exports GetServiceName;
|
||||
exports GetServiceDisplayName;
|
||||
exports GetServiceStatus;
|
||||
exports GetServiceBinaryPath;
|
||||
exports GetServiceDescription;
|
||||
exports GetServiceStartType;
|
||||
exports GetServiceLogon;
|
||||
exports GetServiceFailure;
|
||||
exports GetServiceFailureFlag;
|
||||
exports GetServiceDelayedAutoStartInfo;
|
||||
exports SetServiceDescription;
|
||||
exports SetServiceStartType;
|
||||
exports SetServiceLogon;
|
||||
exports SetServiceBinaryPath;
|
||||
exports SetServiceFailure;
|
||||
exports SetServiceFailureFlag;
|
||||
exports SetServiceDelayedAutoStartInfo;
|
||||
exports ServiceIsRunning;
|
||||
exports ServiceIsStopped;
|
||||
exports ServiceIsPaused;
|
||||
exports RestartService;
|
||||
exports GrantServiceLogonPrivilege;
|
||||
exports RemoveServiceLogonPrivilege;
|
||||
exports GetErrorMessage;
|
||||
|
||||
end.
|
|
@ -0,0 +1,910 @@
|
|||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{9A1C1FE1-FB44-40C4-9E22-99CAE6325532}</ProjectGuid>
|
||||
<ProjectVersion>18.8</ProjectVersion>
|
||||
<FrameworkType>None</FrameworkType>
|
||||
<MainSource>SimpleSC.dpr</MainSource>
|
||||
<Base>True</Base>
|
||||
<Config Condition="'$(Config)'==''">Release</Config>
|
||||
<Platform Condition="'$(Platform)'==''">Win32</Platform>
|
||||
<TargetedPlatforms>1</TargetedPlatforms>
|
||||
<AppType>Library</AppType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
|
||||
<Base_Win32>true</Base_Win32>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
|
||||
<Base_Win64>true</Base_Win64>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
|
||||
<Cfg_2>true</Cfg_2>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
|
||||
<Cfg_2_Win32>true</Cfg_2_Win32>
|
||||
<CfgParent>Cfg_2</CfgParent>
|
||||
<Cfg_2>true</Cfg_2>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base)'!=''">
|
||||
<DCC_UsePackage>bindcompfmx;fmx;rtl;dbrtl;IndySystem;DbxClientDriver;bindcomp;inetdb;DBXInterBaseDriver;DataSnapCommon;DataSnapClient;DataSnapServer;DataSnapProviderClient;xmlrtl;DbxCommonDriver;IndyProtocols;DBXMySQLDriver;dbxcds;bindengine;soaprtl;DBXOracleDriver;dsnap;DBXInformixDriver;IndyCore;fmxase;DBXFirebirdDriver;inet;fmxobj;inetdbxpress;DBXSybaseASADriver;fmxdae;dbexpress;DataSnapIndy10ServerTransport;IPIndyImpl;$(DCC_UsePackage)</DCC_UsePackage>
|
||||
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
|
||||
<GenDll>true</GenDll>
|
||||
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
|
||||
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
|
||||
<DCC_E>false</DCC_E>
|
||||
<DCC_N>false</DCC_N>
|
||||
<DCC_S>false</DCC_S>
|
||||
<DCC_F>false</DCC_F>
|
||||
<DCC_K>false</DCC_K>
|
||||
<SanitizedProjectName>SimpleSC</SanitizedProjectName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_Win32)'!=''">
|
||||
<Manifest_File>None</Manifest_File>
|
||||
<DCC_ExeOutput>C:\Developing\NSIS Simple Service Control - Unicode\</DCC_ExeOutput>
|
||||
<DCC_DcuOutput>C:\Developing\NSIS Simple Service Control - Unicode\</DCC_DcuOutput>
|
||||
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
|
||||
<DCC_UsePackage>frx16;TeeDB;Rave100VCL;vclib;Tee;inetdbbde;DBXOdbcDriver;svnui;ibxpress;DBXSybaseASEDriver;vclimg;frxDB16;intrawebdb_120_160;fmi;fs16;TeeUI;vclactnband;FMXTee;vcldb;vcldsnap;bindcompvcl;vclie;vcltouch;Intraweb_120_160;DBXDb2Driver;websnap;vclribbon;frxe16;fsDB16;vcl;DataSnapConnectors;CloudService;DBXMSSQLDriver;FmxTeeUI;dsnapcon;vclx;webdsnap;svn;bdertl;CodeSiteExpressPkg;adortl;vcldbx;VclSmp;$(DCC_UsePackage)</DCC_UsePackage>
|
||||
<VerInfo_Locale>1033</VerInfo_Locale>
|
||||
<VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_Win64)'!=''">
|
||||
<DCC_UsePackage>DBXOdbcDriver;DBXSybaseASEDriver;vclimg;vclactnband;vcldb;vcldsnap;bindcompvcl;vclie;vcltouch;DBXDb2Driver;websnap;vcl;DBXMSSQLDriver;dsnapcon;vclx;webdsnap;VclSmp;$(DCC_UsePackage)</DCC_UsePackage>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_2)'!=''">
|
||||
<Manifest_File>None</Manifest_File>
|
||||
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
|
||||
<DCC_ImportedDataReferences>false</DCC_ImportedDataReferences>
|
||||
<VerInfo_Locale>1031</VerInfo_Locale>
|
||||
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
|
||||
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
|
||||
<DCC_DebugInformation>0</DCC_DebugInformation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
|
||||
<DCC_ExeOutput>C:\Developing\NSIS Simple Service Control - Unicode\</DCC_ExeOutput>
|
||||
<DCC_DcuOutput>C:\Developing\NSIS Simple Service Control - Unicode\</DCC_DcuOutput>
|
||||
<VerInfo_Locale>1033</VerInfo_Locale>
|
||||
<Manifest_File>(Ohne)</Manifest_File>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<DelphiCompile Include="$(MainSource)">
|
||||
<MainSource>MainSource</MainSource>
|
||||
</DelphiCompile>
|
||||
<DCCReference Include="NSIS.pas"/>
|
||||
<DCCReference Include="ServiceControl.pas"/>
|
||||
<DCCReference Include="LSASecurityControl.pas"/>
|
||||
<BuildConfiguration Include="Release">
|
||||
<Key>Cfg_2</Key>
|
||||
<CfgParent>Base</CfgParent>
|
||||
</BuildConfiguration>
|
||||
<BuildConfiguration Include="Base">
|
||||
<Key>Base</Key>
|
||||
</BuildConfiguration>
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
|
||||
<Borland.ProjectType/>
|
||||
<BorlandProject>
|
||||
<Delphi.Personality>
|
||||
<VersionInfo>
|
||||
<VersionInfo Name="IncludeVerInfo">False</VersionInfo>
|
||||
<VersionInfo Name="AutoIncBuild">False</VersionInfo>
|
||||
<VersionInfo Name="MajorVer">1</VersionInfo>
|
||||
<VersionInfo Name="MinorVer">0</VersionInfo>
|
||||
<VersionInfo Name="Release">0</VersionInfo>
|
||||
<VersionInfo Name="Build">0</VersionInfo>
|
||||
<VersionInfo Name="Debug">False</VersionInfo>
|
||||
<VersionInfo Name="PreRelease">False</VersionInfo>
|
||||
<VersionInfo Name="Special">False</VersionInfo>
|
||||
<VersionInfo Name="Private">False</VersionInfo>
|
||||
<VersionInfo Name="DLL">False</VersionInfo>
|
||||
<VersionInfo Name="Locale">1031</VersionInfo>
|
||||
<VersionInfo Name="CodePage">1252</VersionInfo>
|
||||
</VersionInfo>
|
||||
<VersionInfoKeys>
|
||||
<VersionInfoKeys Name="CompanyName"/>
|
||||
<VersionInfoKeys Name="FileDescription"/>
|
||||
<VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
|
||||
<VersionInfoKeys Name="InternalName"/>
|
||||
<VersionInfoKeys Name="LegalCopyright"/>
|
||||
<VersionInfoKeys Name="LegalTrademarks"/>
|
||||
<VersionInfoKeys Name="OriginalFilename"/>
|
||||
<VersionInfoKeys Name="ProductName"/>
|
||||
<VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
|
||||
<VersionInfoKeys Name="Comments"/>
|
||||
</VersionInfoKeys>
|
||||
<Source>
|
||||
<Source Name="MainSource">SimpleSC.dpr</Source>
|
||||
</Source>
|
||||
<Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k260.bpl">Microsoft Office 2000 Beispiele für gekapselte Komponenten für Automatisierungsserver</Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDSBIN)\dclofficexp260.bpl">Microsoft Office XP Beispiele für gekapselte Komponenten für Automation Server</Excluded_Packages>
|
||||
</Excluded_Packages>
|
||||
</Delphi.Personality>
|
||||
<Deployment Version="3">
|
||||
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
|
||||
<Platform Name="OSX32">
|
||||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
|
||||
<Platform Name="iOSSimulator">
|
||||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libpcre.dylib" Class="DependencyModule">
|
||||
<Platform Name="iOSSimulator">
|
||||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
<DeployClass Name="AdditionalDebugSymbols">
|
||||
<Platform Name="OSX32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidClassesDexFile">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>classes</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>classes</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidFileProvider">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\xml</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\xml</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidGDBServer">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidLibnativeArmeabiFile">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>library\lib\armeabi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidLibnativeArmeabiv7aFile">
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidLibnativeMipsFile">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\mips</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>library\lib\mips</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidServiceOutput">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidServiceOutput_Android32">
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidSplashImageDef">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\drawable</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidSplashStyles">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\values</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\values</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidSplashStylesV21">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\values-v21</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\values-v21</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_Colors">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\values</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\values</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_DefaultAppIcon">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\drawable</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon144">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon36">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-ldpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\drawable-ldpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon48">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-mdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\drawable-mdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon72">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-hdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\drawable-hdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon96">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-xhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\drawable-xhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_NotificationIcon24">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-mdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\drawable-mdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_NotificationIcon36">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-hdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\drawable-hdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_NotificationIcon48">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-xhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\drawable-xhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_NotificationIcon72">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_NotificationIcon96">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_SplashImage426">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-small</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\drawable-small</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_SplashImage470">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-normal</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\drawable-normal</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_SplashImage640">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-large</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\drawable-large</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_SplashImage960">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-xlarge</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\drawable-xlarge</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_Strings">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\values</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>res\values</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="DebugSymbols">
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="DependencyFramework">
|
||||
<Platform Name="OSX32">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.framework</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.framework</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="DependencyModule">
|
||||
<Platform Name="OSX32">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
<Extensions>.dll;.bpl</Extensions>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Required="true" Name="DependencyPackage">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
<Extensions>.bpl</Extensions>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="File">
|
||||
<Platform Name="Android">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch1024x768">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch1536x2048">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch1668">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch1668x2388">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch2048x1536">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch2048x2732">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch2224">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch2388x1668">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch2732x2048">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch768x1024">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch1125">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch1136x640">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch1242">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch1242x2688">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch1334">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch1792">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch2208">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch2436">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch2688x1242">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch320">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch640">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch640x1136">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch750">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch828">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectAndroidManifest">
|
||||
<Platform Name="Android">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectiOSDeviceDebug">
|
||||
<Platform Name="iOSDevice32">
|
||||
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectiOSDeviceResourceRules"/>
|
||||
<DeployClass Name="ProjectiOSEntitlements"/>
|
||||
<DeployClass Name="ProjectiOSInfoPList"/>
|
||||
<DeployClass Name="ProjectiOSResource">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectOSXDebug"/>
|
||||
<DeployClass Name="ProjectOSXEntitlements"/>
|
||||
<DeployClass Name="ProjectOSXInfoPList"/>
|
||||
<DeployClass Name="ProjectOSXResource">
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents\Resources</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<RemoteDir>Contents\Resources</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Required="true" Name="ProjectOutput">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Linux64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectOutput_Android32">
|
||||
<Platform Name="Android64">
|
||||
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectUWPManifest">
|
||||
<Platform Name="Win32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="UWP_DelphiLogo150">
|
||||
<Platform Name="Win32">
|
||||
<RemoteDir>Assets</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win64">
|
||||
<RemoteDir>Assets</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="UWP_DelphiLogo44">
|
||||
<Platform Name="Win32">
|
||||
<RemoteDir>Assets</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win64">
|
||||
<RemoteDir>Assets</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
|
||||
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
|
||||
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="OSX64" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
|
||||
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
|
||||
</Deployment>
|
||||
<Platforms>
|
||||
<Platform value="Win32">True</Platform>
|
||||
<Platform value="Win64">False</Platform>
|
||||
</Platforms>
|
||||
<ModelSupport>False</ModelSupport>
|
||||
</BorlandProject>
|
||||
<ProjectFileVersion>12</ProjectFileVersion>
|
||||
</ProjectExtensions>
|
||||
<Import Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')" Project="$(BDS)\Bin\CodeGear.Delphi.Targets"/>
|
||||
<Import Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')" Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj"/>
|
||||
<Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
|
||||
</Project>
|
Binary file not shown.
181
desktop/tauri/src-tauri/templates/nsis/install_hooks.nsh
Normal file
181
desktop/tauri/src-tauri/templates/nsis/install_hooks.nsh
Normal file
|
@ -0,0 +1,181 @@
|
|||
!include LogicLib.nsh
|
||||
|
||||
!addplugindir "..\..\..\..\templates\NSIS_Simple_Service_Plugin_Unicode_1.30"
|
||||
|
||||
var oldInstallationDir
|
||||
var dataDir
|
||||
|
||||
!macro NSIS_HOOK_PREINSTALL
|
||||
; Abort if old service is running
|
||||
SimpleSC::ServiceIsStopped "PortmasterCore"
|
||||
Pop $0
|
||||
Pop $1
|
||||
${If} $0 == 0
|
||||
${If} $1 == 0
|
||||
MessageBox MB_OK "Portmaster service is running. Stop it and run the installer again."
|
||||
Abort
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
|
||||
File "..\..\..\..\binary\portmaster-core.exe"
|
||||
File "..\..\..\..\binary\portmaster-kext.sys"
|
||||
File "..\..\..\..\binary\portmaster-core.dll"
|
||||
File "..\..\..\..\binary\WebView2Loader.dll"
|
||||
File "..\..\..\..\binary\portmaster.zip"
|
||||
File "..\..\..\..\binary\assets.zip"
|
||||
|
||||
SetOutPath "$COMMONPROGRAMDATA\Portmaster\intel"
|
||||
|
||||
File "..\..\..\..\intel\index.json"
|
||||
File "..\..\..\..\intel\base.dsdl"
|
||||
File "..\..\..\..\intel\geoipv4.mmdb"
|
||||
File "..\..\..\..\intel\geoipv6.mmdb"
|
||||
File "..\..\..\..\intel\index.dsd"
|
||||
File "..\..\..\..\intel\intermediate.dsdl"
|
||||
File "..\..\..\..\intel\urgent.dsdl"
|
||||
File "..\..\..\..\intel\main-intel.yaml"
|
||||
File "..\..\..\..\intel\notifications.yaml"
|
||||
File "..\..\..\..\intel\news.yaml"
|
||||
|
||||
; restire previous state
|
||||
SetOutPath "$INSTDIR"
|
||||
|
||||
!macroend
|
||||
|
||||
;--------------------------------------------------
|
||||
; Post-install hook:
|
||||
; - Remove old service
|
||||
; - Installs the service
|
||||
!macro NSIS_HOOK_POSTINSTALL
|
||||
DetailPrint "Installing service"
|
||||
; Remove old service
|
||||
SimpleSC::RemoveService "PortmasterCore"
|
||||
|
||||
; Install the service:
|
||||
; Parameters:
|
||||
; 1. Service Name: "PortmasterCore"
|
||||
; 2. Display Name: "Portmaster Core"
|
||||
; 3. Service Type: "16" for SERVICE_WIN32_OWN_PROCESS
|
||||
; 4. Start Type: "2" for SERVICE_AUTO_START
|
||||
; 5. Binary Path: Executable with arguments.
|
||||
; 6 & 7. Dependencies and account info (empty uses defaults).
|
||||
SimpleSC::InstallService "PortmasterCore" "Portmaster Core" 16 2 "$INSTDIR\portmaster-core.exe --log-dir=%PROGRAMDATA%\Portmaster\logs" "" "" ""
|
||||
Pop $0 ; returns error code (0 on success)
|
||||
${If} $0 != 0
|
||||
SimpleSC::GetErrorMessage $0
|
||||
Pop $0
|
||||
MessageBox MB_OK "Service creation failed. Error: $0"
|
||||
Abort
|
||||
${EndIf}
|
||||
|
||||
SimpleSC::SetServiceDescription "PortmasterCore" "Portmaster Application Firewall - Core Service"
|
||||
|
||||
StrCpy $oldInstallationDir "$COMMONPROGRAMDATA\Safing\Portmaster"
|
||||
StrCpy $dataDir "$COMMONPROGRAMDATA\Portmaster"
|
||||
|
||||
; Check if the folder exists
|
||||
IfFileExists "$oldInstallationDir\*.*" 0 Finish
|
||||
|
||||
; Stop if the migration flag(file) already exists.
|
||||
IfFileExists "$oldInstallationDir\migrated.txt" Finish 0
|
||||
|
||||
; Copy files
|
||||
DetailPrint "Migrating config from old installation: $oldInstallationDir"
|
||||
|
||||
CreateDirectory "$dataDir"
|
||||
CreateDirectory "$dataDir\databases"
|
||||
CopyFiles "$oldInstallationDir\config.json" "$dataDir"
|
||||
CopyFiles "$oldInstallationDir\databases\*.*" "$dataDir\databases"
|
||||
|
||||
; Create empty file to indicate that the data has already been migrated.
|
||||
FileOpen $0 "$oldInstallationDir\migrated.txt" w
|
||||
FileClose $0
|
||||
|
||||
; Delete v1 shortcuts
|
||||
RMDir /r "$SMPROGRAMS\Portmaster"
|
||||
Delete "$SMSTARTUP\Portmaster Notifier.lnk"
|
||||
|
||||
; Delete v1 old binaries
|
||||
Delete "$oldInstallationDir\portmaster-uninstaller.exe"
|
||||
Delete "$oldInstallationDir\portmaster-start.exe"
|
||||
Delete "$oldInstallationDir\portmaster.ico"
|
||||
RMDir /r "$oldInstallationDir\exec"
|
||||
RMDir /r "$oldInstallationDir\updates"
|
||||
RMDir /r "$oldInstallationDir\databases\cache"
|
||||
RMDir /r "$oldInstallationDir\intel"
|
||||
|
||||
; Delete the link to the ProgramData folder
|
||||
RMDir /r "$PROGRAMFILES\Safing"
|
||||
|
||||
; Delete v1 user shortcut if its there.
|
||||
SetShellVarContext current
|
||||
Delete "$AppData\Microsoft\Windows\Start Menu\Programs\Portmaster.lnk"
|
||||
SetShellVarContext all
|
||||
|
||||
; Delete v1 registry values
|
||||
DeleteRegKey HKLM "Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Portmaster"
|
||||
|
||||
Finish:
|
||||
|
||||
!macroend
|
||||
|
||||
;--------------------------------------------------
|
||||
; Pre-uninstall hook:
|
||||
; - Stops and removes the service.
|
||||
!macro NSIS_HOOK_PREUNINSTALL
|
||||
DetailPrint "Stopping service"
|
||||
; Trigger service stop. In the worst case the service should stop in ~60 seconds.
|
||||
SimpleSC::StopService "PortmasterCore" 1 90
|
||||
Pop $0
|
||||
${If} $0 != 0
|
||||
DetailPrint "Failed to stop PortmasterCore service. Error: $0"
|
||||
${Else}
|
||||
DetailPrint "Service PortmasterCore stopped successfully."
|
||||
${EndIf}
|
||||
|
||||
DetailPrint "Removing service"
|
||||
SimpleSC::RemoveService "PortmasterCore"
|
||||
Pop $0
|
||||
${If} $0 != 0
|
||||
DetailPrint "Failed to remove PortmasterCore service. Error: $0"
|
||||
${Else}
|
||||
DetailPrint "Service PortmasterCore removed successfully."
|
||||
${EndIf}
|
||||
!macroend
|
||||
|
||||
;--------------------------------------------------
|
||||
; Post-uninstall hook:
|
||||
; - Delete files
|
||||
!macro NSIS_HOOK_POSTUNINSTALL
|
||||
; Delete binarys
|
||||
Delete /REBOOTOK "$INSTDIR\index.json"
|
||||
Delete /REBOOTOK "$INSTDIR\portmaster-core.exe"
|
||||
Delete /REBOOTOK "$INSTDIR\portmaster-kext.sys"
|
||||
Delete /REBOOTOK "$INSTDIR\portmaster-core.dll"
|
||||
Delete /REBOOTOK "$INSTDIR\WebView2Loader.dll"
|
||||
Delete /REBOOTOK "$INSTDIR\portmaster.zip"
|
||||
Delete /REBOOTOK "$INSTDIR\assets.zip"
|
||||
RMDir /r /REBOOTOK "$INSTDIR"
|
||||
|
||||
; Delete Tauri leftovers
|
||||
RMDir /r /REBOOTOK "$APPDATA\Portmaster"
|
||||
|
||||
; Delete intel data
|
||||
Delete /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\intel\index.json"
|
||||
Delete /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\intel\base.dsdl"
|
||||
Delete /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\intel\geoipv4.mmdb"
|
||||
Delete /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\intel\geoipv6.mmdb"
|
||||
Delete /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\intel\index.dsd"
|
||||
Delete /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\intel\intermediate.dsdl"
|
||||
Delete /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\intel\urgent.dsdl"
|
||||
Delete /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\intel\main-intel.yaml"
|
||||
Delete /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\intel\notifications.yaml"
|
||||
Delete /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\intel\news.yaml"
|
||||
RMDir /r /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\intel"
|
||||
|
||||
${If} $DeleteAppDataCheckboxState = 1
|
||||
RMDir /r /REBOOTOK "$COMMONPROGRAMDATA\Portmaster"
|
||||
RMDir /r /REBOOTOK "$COMMONPROGRAMDATA\Safing"
|
||||
${EndIf}
|
||||
|
||||
!macroend
|
|
@ -1,37 +0,0 @@
|
|||
!macro NSIS_HOOK_PREINSTALL
|
||||
; Current working directory is <project-dir>\desktop\tauri\src-tauri\target\release\nsis\x64
|
||||
|
||||
SetOutPath "$INSTDIR"
|
||||
|
||||
File "..\..\..\..\binary\index.json"
|
||||
File "..\..\..\..\binary\portmaster-core.exe"
|
||||
File "..\..\..\..\binary\portmaster-kext.sys"
|
||||
File "..\..\..\..\binary\portmaster-core.dll"
|
||||
File "..\..\..\..\binary\WebView2Loader.dll"
|
||||
File "..\..\..\..\binary\portmaster.zip"
|
||||
File "..\..\..\..\binary\assets.zip"
|
||||
|
||||
SetOutPath "$COMMONPROGRAMDATA\Portmaster\intel"
|
||||
|
||||
File "..\..\..\..\intel\index.json"
|
||||
File "..\..\..\..\intel\base.dsdl"
|
||||
File "..\..\..\..\intel\geoipv4.mmdb"
|
||||
File "..\..\..\..\intel\geoipv6.mmdb"
|
||||
File "..\..\..\..\intel\index.dsd"
|
||||
File "..\..\..\..\intel\intermediate.dsdl"
|
||||
File "..\..\..\..\intel\urgent.dsdl"
|
||||
|
||||
; restire previous state
|
||||
SetOutPath "$INSTDIR"
|
||||
|
||||
!macroend
|
||||
|
||||
!macro NSIS_HOOK_POSTINSTALL
|
||||
ExecWait 'sc.exe create PortmasterCore binPath= "$INSTDIR\portmaster-core.exe --log-dir=%PROGRAMDATA%\Portmaster\logs"'
|
||||
!macroend
|
||||
|
||||
!macro NSIS_HOOK_PREUNINSTALL
|
||||
ExecWait 'sc.exe stop PortmasterCore'
|
||||
ExecWait 'sc.exe delete PortmasterCore'
|
||||
!macroend
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<CustomAction Id="InstallPortmasterService"
|
||||
Directory="INSTALLDIR"
|
||||
ExeCommand="sc.exe create PortmasterCore binPath= "[INSTALLDIR]portmaster-core.exe --log-dir=%PROGRAMDATA%\Portmaster\logs""
|
||||
Execute="commit"
|
||||
Return="check"
|
||||
Impersonate="no"
|
||||
/>
|
||||
<CustomAction Id="StopPortmasterService"
|
||||
Directory="INSTALLDIR"
|
||||
ExeCommand="sc.exe stop PortmasterCore"
|
||||
Execute="commit"
|
||||
Return="ignore"
|
||||
Impersonate="no"
|
||||
/>
|
||||
<CustomAction Id="DeletePortmasterService"
|
||||
Directory="INSTALLDIR"
|
||||
ExeCommand="sc.exe delete PortmasterCore"
|
||||
Execute="commit"
|
||||
Return="ignore"
|
||||
Impersonate="no"
|
||||
/>
|
||||
<InstallExecuteSequence>
|
||||
<Custom Action="InstallPortmasterService" Before='InstallFinalize'>
|
||||
<![CDATA[NOT Installed]]>
|
||||
</Custom>
|
||||
<Custom Action="StopPortmasterService" Before='InstallFinalize'>
|
||||
REMOVE
|
||||
</Custom>
|
||||
<Custom Action="DeletePortmasterService" Before='InstallFinalize'>
|
||||
REMOVE
|
||||
</Custom>
|
||||
</InstallExecuteSequence>
|
||||
</Fragment>
|
||||
</Wix>
|
44
desktop/tauri/src-tauri/templates/wix/CheckServiceStatus.vbs
Normal file
44
desktop/tauri/src-tauri/templates/wix/CheckServiceStatus.vbs
Normal file
|
@ -0,0 +1,44 @@
|
|||
Option Explicit
|
||||
|
||||
Dim objShell, objExec, strOutput, arrLines, i, arrStatus
|
||||
|
||||
' Create an instance of the WScript.Shell object
|
||||
Set objShell = CreateObject("WScript.Shell")
|
||||
|
||||
' Run the sc.exe command to query the service
|
||||
Set objExec = objShell.Exec("cmd /c sc.exe query PortmasterCore")
|
||||
|
||||
' Initialize an empty string to store the output
|
||||
strOutput = ""
|
||||
|
||||
' Read all output from the command line
|
||||
Do While Not objExec.StdOut.AtEndOfStream
|
||||
strOutput = strOutput & objExec.StdOut.ReadLine() & vbCrLf
|
||||
Loop
|
||||
|
||||
' Split the output into lines
|
||||
arrLines = Split(strOutput, vbCrLf)
|
||||
|
||||
' Example Output
|
||||
' SERVICE_NAME: PortmasterCore
|
||||
' TYPE : 10 WIN32_OWN_PROCESS
|
||||
' STATE : 1 STOPPED
|
||||
' WIN32_EXIT_CODE : 1077 (0x435)
|
||||
' SERVICE_EXIT_CODE : 0 (0x0)
|
||||
' CHECKPOINT : 0x0
|
||||
' WAIT_HINT : 0x0
|
||||
|
||||
For i = LBound(arrLines) To UBound(arrLines)
|
||||
' Example line: STATE : 1 STOPPED
|
||||
If InStr(arrLines(i), "STATE") > 0 Then
|
||||
' Extract and display the service state
|
||||
' Example string: "1 STOPPED"
|
||||
arrStatus = Split(Trim(Mid(arrLines(i), InStr(arrLines(i), ":") + 1)), " ")
|
||||
' Anything other the STOPPED consider as running
|
||||
If Not arrStatus(2) = "STOPPED" Then
|
||||
MsgBox("Portmaster service is running. Stop it and run the installer again.")
|
||||
' Notify the installer that it should fail.
|
||||
WScript.Quit 1
|
||||
End If
|
||||
End If
|
||||
Next
|
78
desktop/tauri/src-tauri/templates/wix/Migration.vbs
Normal file
78
desktop/tauri/src-tauri/templates/wix/Migration.vbs
Normal file
|
@ -0,0 +1,78 @@
|
|||
Dim FSO
|
||||
Set FSO = CreateObject("Scripting.FileSystemObject")
|
||||
|
||||
Dim customData, args, oldInstallationDir, migrationFlagFile, newDataDir, doMigration
|
||||
customData = Session.Property("CustomActionData")
|
||||
|
||||
' Split the string by commas
|
||||
args = Split(customData, ",")
|
||||
|
||||
' Access individual arguments
|
||||
Dim commonAppDataFolder, programMenuFolder, startupFolder, appDataFolder
|
||||
commonAppDataFolder = Trim(args(0))
|
||||
programMenuFolder = Trim(args(1))
|
||||
startupFolder = Trim(args(2))
|
||||
appDataFolder = Trim(args(3))
|
||||
|
||||
' Read variables from the session object
|
||||
oldInstallationDir = commonAppDataFolder & "Safing\Portmaster\"
|
||||
newDataDir = commonAppDataFolder & "Portmaster"
|
||||
migrationFlagFile = oldInstallationDir & "migrated.txt"
|
||||
doMigration = true
|
||||
|
||||
' Check for existing installtion
|
||||
If Not fso.FolderExists(oldInstallationDir) Then
|
||||
doMigration = false
|
||||
End If
|
||||
|
||||
' Check if migration was already done
|
||||
If fso.FileExists(migrationFlagFile) Then
|
||||
doMigration = false
|
||||
End If
|
||||
|
||||
If doMigration Then
|
||||
' Copy the config file
|
||||
dim configFile
|
||||
configFile = "config.json"
|
||||
If fso.FileExists(oldInstallationDir & configFile) Then
|
||||
fso.CopyFile oldInstallationDir & configFile, newDataDir & configFile
|
||||
End If
|
||||
|
||||
' Copy the database folder
|
||||
dim databaseFolder
|
||||
databaseFolder = "databases"
|
||||
If fso.FolderExists(oldInstallationDir & databaseFolder) Then
|
||||
fso.CopyFolder oldInstallationDir & databaseFolder, newDataDir & databaseFolder
|
||||
End If
|
||||
|
||||
' Delete shortcuts
|
||||
dim shortcutsFolder
|
||||
notifierShortcut = programMenuFolder & "Portmaster/Portmaster Notifier.lnk"
|
||||
If fso.FileExists(notifierShortcut) Then
|
||||
fso.DeleteFile notifierShortcut, True
|
||||
End If
|
||||
|
||||
' Delete startup shortcut
|
||||
dim srartupFile
|
||||
srartupFile = startupFolder & "Portmaster Notifier.lnk"
|
||||
If fso.FileExists(srartupFile) Then
|
||||
fso.DeleteFile srartupFile, True
|
||||
End If
|
||||
|
||||
' Delete shortuct in user folder
|
||||
dim userShortcut
|
||||
userShortcut = appDataFolder & "Microsoft\Windows\Start Menu\Programs\Portmaster.lnk"
|
||||
If fso.FileExists(userShortcut) Then
|
||||
fso.DeleteFile userShortcut, True
|
||||
End If
|
||||
|
||||
' Delete the old installer
|
||||
dim oldUninstaller
|
||||
oldUninstaller = oldInstallationDir & "portmaster-uninstaller.exe"
|
||||
If fso.FileExists(oldUninstaller) Then
|
||||
fso.DeleteFile oldUninstaller, True
|
||||
End If
|
||||
|
||||
' Set the migration flag file
|
||||
fso.CreateTextFile(migrationFlagFile).Close
|
||||
End If
|
|
@ -12,8 +12,6 @@
|
|||
|
||||
<Fragment>
|
||||
<Component Id="BinaryFiles" Directory="INSTALLDIR" Guid="850cdd31-424d-45f5-b8f0-95df950ebd0d">
|
||||
<File Id="BinIndexJson" Source="..\..\..\..\binary\index.json" />
|
||||
<File Id="PortmasterCoreExe" Source="..\..\..\..\binary\portmaster-core.exe" />
|
||||
<File Id="PortmasterCoreDLL" Source="..\..\..\..\binary\portmaster-core.dll" />
|
||||
<File Id="PortmasterKextSys" Source="..\..\..\..\binary\portmaster-kext.sys" />
|
||||
<File Id="WebView2Loader" Source="..\..\..\..\binary\WebView2Loader.dll" />
|
||||
|
@ -29,6 +27,33 @@
|
|||
<File Id="IndexDsd" Source="..\..\..\..\intel\index.dsd" />
|
||||
<File Id="IntermediateDsdl" Source="..\..\..\..\intel\intermediate.dsdl" />
|
||||
<File Id="UrgentDsdl" Source="..\..\..\..\intel\urgent.dsdl" />
|
||||
<File Id="MainIntelYaml" Source="..\..\..\..\intel\main-intel.yaml" />
|
||||
<File Id="NotificationsYaml" Source="..\..\..\..\intel\notifications.yaml" />
|
||||
<File Id="NewsYaml" Source="..\..\..\..\intel\news.yaml" />
|
||||
</Component>
|
||||
|
||||
<Component Id="PortmasterCoreService" Directory="INSTALLDIR" Guid="76ebd748-d620-484b-9035-5a64bbe2c26d">
|
||||
<File Id="PortmasterCoreExe" Source="..\..\..\..\binary\portmaster-core.exe" />
|
||||
<ServiceInstall
|
||||
Id="PortmasterServiceInstall"
|
||||
Type="ownProcess"
|
||||
Name="PortmasterCore"
|
||||
DisplayName="Portmaster Core"
|
||||
Description="Portmaster Application Firewall - Core Service"
|
||||
Start="auto"
|
||||
ErrorControl="normal"
|
||||
Vital="yes"
|
||||
Interactive="no"
|
||||
Arguments="--log-dir=%PROGRAMDATA%\Portmaster\logs"
|
||||
Account="LocalSystem" />
|
||||
|
||||
<ServiceControl
|
||||
Id="PortmasterServiceDeleteExisting"
|
||||
Name="PortmasterCore"
|
||||
Remove="uninstall"
|
||||
Stop="both"
|
||||
Wait="yes"
|
||||
/>
|
||||
</Component>
|
||||
</Fragment>
|
||||
|
||||
|
@ -36,6 +61,7 @@
|
|||
<ComponentGroup Id="BinaryAndIntelFiles">
|
||||
<ComponentRef Id="BinaryFiles" />
|
||||
<ComponentRef Id="IntelFiles" />
|
||||
<ComponentRef Id="PortmasterCoreService" />
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
</Wix>
|
|
@ -70,9 +70,12 @@
|
|||
<Property Id="ARPURLUPDATEINFO" Value="{{homepage}}"/>
|
||||
{{/if}}
|
||||
|
||||
<!-- initialize with previous InstallDir -->
|
||||
<Property Id="INSTALLDIR">
|
||||
<RegistrySearch Id="PrevInstallDirReg" Root="HKCU" Key="Software\\{{manufacturer}}\\{{product_name}}" Name="InstallDir" Type="raw"/>
|
||||
<!-- First attempt: Search for "InstallDir" -->
|
||||
<RegistrySearch Id="PrevInstallDirWithName" Root="HKCU" Key="Software\\{{manufacturer}}\\{{product_name}}" Name="InstallDir" Type="raw" />
|
||||
|
||||
<!-- Second attempt: If the first fails, search for the default key value (this is how the nsis installer currently stores the path) -->
|
||||
<RegistrySearch Id="PrevInstallDirNoName" Root="HKCU" Key="Software\\{{manufacturer}}\\{{product_name}}" Type="raw" />
|
||||
</Property>
|
||||
|
||||
<!-- launch app checkbox -->
|
||||
|
@ -161,6 +164,7 @@
|
|||
</Component>
|
||||
<Component Id="UpdateTaskInstaller" Guid="011F25ED-9BE3-50A7-9E9B-3519ED2B9932" Win64="$(var.Win64)">
|
||||
<File Id="UpdateTaskInstaller" Source="install-task.ps1" KeyPath="yes" Checksum="yes"/>
|
||||
|
||||
</Component>
|
||||
<Component Id="UpdateTaskUninstaller" Guid="D4F6CC3F-32DC-5FD0-95E8-782FFD7BBCE1" Win64="$(var.Win64)">
|
||||
<File Id="UpdateTaskUninstaller" Source="uninstall-task.ps1" KeyPath="yes" Checksum="yes"/>
|
||||
|
@ -323,6 +327,7 @@
|
|||
Execute="commit"
|
||||
Impersonate="yes"
|
||||
ExeCommand="powershell.exe -WindowStyle hidden .\install-task.ps1" />
|
||||
|
||||
<InstallExecuteSequence>
|
||||
<Custom Action='CreateUpdateTask' Before='InstallFinalize'>
|
||||
NOT(REMOVE)
|
||||
|
@ -348,9 +353,11 @@
|
|||
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLDIR]" After="CostFinalize"/>
|
||||
|
||||
<!-- Service fragments -->
|
||||
<CustomActionRef Id='InstallPortmasterService' />
|
||||
<CustomActionRef Id='StopPortmasterService' />
|
||||
<CustomActionRef Id='DeletePortmasterService' />
|
||||
<CustomActionRef Id='MigrationPropertySet' />
|
||||
<CustomActionRef Id='Migration' />
|
||||
<!-- Uncommenting the next line will cause the installer to check if the old service is running and fail. Without, it will automatically stop and remove the old service without notifing the user. -->
|
||||
<!-- <CustomActionRef Id='CheckServiceStatus' /> -->
|
||||
<!-- End Service fragments -->
|
||||
|
||||
</Product>
|
||||
</Wix>
|
|
@ -70,9 +70,12 @@
|
|||
<Property Id="ARPURLUPDATEINFO" Value="{{homepage}}"/>
|
||||
{{/if}}
|
||||
|
||||
<!-- initialize with previous InstallDir -->
|
||||
<Property Id="INSTALLDIR">
|
||||
<RegistrySearch Id="PrevInstallDirReg" Root="HKCU" Key="Software\\{{manufacturer}}\\{{product_name}}" Name="InstallDir" Type="raw"/>
|
||||
<!-- First attempt: Search for "InstallDir" -->
|
||||
<RegistrySearch Id="PrevInstallDirWithName" Root="HKCU" Key="Software\\{{manufacturer}}\\{{product_name}}" Name="InstallDir" Type="raw" />
|
||||
|
||||
<!-- Second attempt: If the first fails, search for the default key value (this is how the nsis installer currently stores the path) -->
|
||||
<RegistrySearch Id="PrevInstallDirNoName" Root="HKCU" Key="Software\\{{manufacturer}}\\{{product_name}}" Type="raw" />
|
||||
</Property>
|
||||
|
||||
<!-- launch app checkbox -->
|
28
desktop/tauri/src-tauri/templates/wix/migration.wxs
Normal file
28
desktop/tauri/src-tauri/templates/wix/migration.wxs
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
|
||||
<!-- Load the VBscript -->
|
||||
<Binary Id="Migration.vbs" SourceFile="..\..\..\..\templates\wix\Migration.vbs" />
|
||||
|
||||
<!-- VBscript script to copy the files from the old installation -->
|
||||
<CustomAction
|
||||
Id="Migration"
|
||||
VBScriptCall=""
|
||||
BinaryKey="Migration.vbs"
|
||||
Return="check"
|
||||
Impersonate="no"
|
||||
Execute="deferred"
|
||||
/>
|
||||
|
||||
<!-- This passes the path to CommonAppDataFolder path (usually "C:\ProgramData\") to the vbscirt custom action -->
|
||||
<CustomAction Id="MigrationPropertySet" Property="Migration" Value="[CommonAppDataFolder], [ProgramMenuFolder], [StartupFolder], [AppDataFolder]" />
|
||||
|
||||
<!-- Check if service is running -->
|
||||
<InstallExecuteSequence>
|
||||
<Custom Action="MigrationPropertySet" Before="Migration">NOT(REMOVE)</Custom>
|
||||
<Custom Action="Migration" Before="InstallFinalize">NOT(REMOVE)</Custom>
|
||||
</InstallExecuteSequence>
|
||||
|
||||
</Fragment>
|
||||
</Wix>
|
20
desktop/tauri/src-tauri/templates/wix/old_service_check.wxs
Normal file
20
desktop/tauri/src-tauri/templates/wix/old_service_check.wxs
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Fragment>
|
||||
<!-- Load the VBscript -->
|
||||
<Binary Id="CheckServiceStatusScript" SourceFile="..\..\..\..\templates\wix\CheckServiceStatus.vbs" />
|
||||
|
||||
<!-- VBscript script custom action to check if the service is running -->
|
||||
<CustomAction
|
||||
Id="CheckServiceStatus"
|
||||
VBScriptCall=""
|
||||
BinaryKey="CheckServiceStatusScript"
|
||||
Return="check" />
|
||||
|
||||
<!-- Check if service is running -->
|
||||
<InstallExecuteSequence>
|
||||
<Custom Action="CheckServiceStatus" Before="InstallInitialize">NOT(REMOVE)</Custom>
|
||||
</InstallExecuteSequence>
|
||||
|
||||
</Fragment>
|
||||
</Wix>
|
101
packaging/README.md
Normal file
101
packaging/README.md
Normal file
|
@ -0,0 +1,101 @@
|
|||
# Generate Windows installer
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Earthly release prep step must be executed and the output `dist` folder should be present in the root directory of the repository. (Probably needs to be done on separate machine running linux or downloaded from the CI)
|
||||
```
|
||||
earthly +release-prep
|
||||
```
|
||||
|
||||
## Building the installers
|
||||
|
||||
In the root directory of the repository, run the PowerShell script to generate the installers:
|
||||
```
|
||||
./packaging\windows\generate_windows_installers.ps1
|
||||
```
|
||||
|
||||
This will output both .exe (NSIS) and .msi (WIX) installers inside the dist folder:
|
||||
```
|
||||
...\Portmaster\dist\windows_amd64\Portmaster_0.1.0_x64-setup.exe
|
||||
...\Portmaster\dist\windows_amd64\Portmaster_0.1.0_x64_en-US.msi
|
||||
```
|
||||
|
||||
## Manual build
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Ensure you have Rust and Cargo installed.
|
||||
Install Tauri CLI by running:
|
||||
```
|
||||
cargo install tauri-cli --version "^2.0.0" --locked
|
||||
```
|
||||
|
||||
### Folder structure
|
||||
|
||||
Create binary and intel folder inside the tauri project folder and place all the necessary files inside.
|
||||
The folder structure should look like this:
|
||||
```
|
||||
...\Portmaster\desktop\tauri\src-tauri\binary
|
||||
assets.zip
|
||||
index.json
|
||||
portmaster-core.dll
|
||||
portmaster-core.exe
|
||||
portmaster-kext.dll
|
||||
portmaster-kext.sys
|
||||
portmaster.zip
|
||||
WebView2Loader.dll
|
||||
|
||||
...\Portmaster\desktop\tauri\src-tauri\intel
|
||||
base.dsdl
|
||||
geoipv4.mmdb
|
||||
geoipv6.mmdb
|
||||
index.dsd
|
||||
index.json
|
||||
intermediate.dsdl
|
||||
main-intel.yaml
|
||||
news.yaml
|
||||
notifications.yaml
|
||||
urgent.dsdl
|
||||
```
|
||||
|
||||
### Building the Installer
|
||||
|
||||
Navigate to the `src-tauri` directory:
|
||||
```
|
||||
cd desktop/tauri/src-tauri
|
||||
```
|
||||
|
||||
Run the following commands to build the installers:
|
||||
|
||||
For both NSIS and WIX installers:
|
||||
```
|
||||
cargo tauri bundle
|
||||
```
|
||||
|
||||
For NSIS installer only:
|
||||
```
|
||||
cargo tauri bundle --bundles nsis
|
||||
```
|
||||
|
||||
For WIX installer only:
|
||||
```
|
||||
cargo tauri bundle --bundles wix
|
||||
```
|
||||
|
||||
The produced files will be in:
|
||||
```
|
||||
target\release\bundle\msi\
|
||||
target\release\bundle\nsis\
|
||||
```
|
||||
|
||||
## Debug MSI Installer
|
||||
|
||||
To see error messages during the build of the installer, run the bundler with the verbose flag:
|
||||
```
|
||||
cargo tauri bundle --bundles msi --verbose
|
||||
```
|
||||
|
||||
To examine the logs during installation, run the installer with the following command:
|
||||
```
|
||||
msiexec /i "target\release\bundle\msi\Portmaster_0.1.0_x64_en-US.msi" /lv install.log
|
||||
```
|
|
@ -34,7 +34,7 @@ AmbientCapabilities=cap_chown cap_kill cap_net_admin cap_net_bind_service cap_ne
|
|||
CapabilityBoundingSet=cap_chown cap_kill cap_net_admin cap_net_bind_service cap_net_broadcast cap_net_raw cap_sys_module cap_sys_ptrace cap_dac_override cap_fowner cap_fsetid cap_sys_resource cap_bpf cap_perfmon
|
||||
StateDirectory=portmaster
|
||||
# TODO(ppacher): add --disable-software-updates once it's merged and the release process changed.
|
||||
WorkingDirectory=/var/lib/portmaster/data
|
||||
WorkingDirectory=/var/lib/portmaster
|
||||
ExecStart=/usr/lib/portmaster/portmaster-core --log-dir=/var/lib/portmaster/log -- $PORTMASTER_ARGS
|
||||
ExecStopPost=-/usr/lib/portmaster/portmaster-core -recover-iptables
|
||||
|
||||
|
|
|
@ -1,20 +1,72 @@
|
|||
#!/bin/bash
|
||||
|
||||
chmod +x /usr/lib/portmaster/portmaster-core
|
||||
echo "[ ] Post-Install script [arg1='$1' arg2='$2']"
|
||||
|
||||
echo "[ ] Stopping old service (if exists)"
|
||||
systemctl stop portmaster.service
|
||||
systemctl disable portmaster.service
|
||||
|
||||
#
|
||||
# Fix selinux permissions for portmaster-core if we have semanage
|
||||
# available.
|
||||
# Migration from v1
|
||||
#
|
||||
OLD_INSTALLATION_DIR="/opt/safing/portmaster"
|
||||
MIGRATED_FILE_FLAG="$OLD_INSTALLATION_DIR/migrated.txt"
|
||||
if [ -d "$OLD_INSTALLATION_DIR" ]; then
|
||||
if [ ! -e "$MIGRATED_FILE_FLAG" ]; then
|
||||
echo "[ ] Starting migration form v1 ..."
|
||||
|
||||
# Because the service file need to change path, first the links to the old service needs to be removed.
|
||||
echo "[ ] V1 migration: Removing old service"
|
||||
rm /etc/systemd/system/portmaster.service # new V2 service registered at "/usr/lib/systemd/system/portmaster.service"
|
||||
|
||||
# Migrate config
|
||||
echo "[ ] V1 migration: Copying V1 configuration"
|
||||
cp -r $OLD_INSTALLATION_DIR/databases /var/lib/portmaster
|
||||
cp -r $OLD_INSTALLATION_DIR/config.json /var/lib/portmaster/config.json
|
||||
|
||||
# Remove shortcut
|
||||
echo "[ ] V1 migration: Removing V1 shortcuts"
|
||||
rm /etc/xdg/autostart/portmaster_notifier.desktop
|
||||
rm /usr/share/applications/portmaster_notifier.desktop
|
||||
|
||||
# Remove V1 files (except configuration)
|
||||
# (keeping V1 configuration for a smooth downgrade, if needed)
|
||||
echo "[ ] V1 migration: Removing V1 files"
|
||||
rm -fr $OLD_INSTALLATION_DIR/exec
|
||||
rm -fr $OLD_INSTALLATION_DIR/logs
|
||||
rm -fr $OLD_INSTALLATION_DIR/updates
|
||||
rm -fr $OLD_INSTALLATION_DIR/databases/cache
|
||||
rm -fr $OLD_INSTALLATION_DIR/databases/icons
|
||||
rm -fr $OLD_INSTALLATION_DIR/databases/history.db
|
||||
|
||||
for file in $OLD_INSTALLATION_DIR/*; do
|
||||
if [ -f "$file" ] && [ "$(basename "$file")" != "config.json" ]; then
|
||||
rm "$file"
|
||||
fi
|
||||
done
|
||||
|
||||
touch $MIGRATED_FILE_FLAG
|
||||
echo "[ ] Migration complete"
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Fix selinux permissions for portmaster-core if we have semanage available.
|
||||
#
|
||||
if command -V semanage >/dev/null 2>&1; then
|
||||
echo "[ ] Fixing SELinux permissions"
|
||||
semanage fcontext -a -t bin_t -s system_u $(realpath /usr/lib)'/portmaster/portmaster-core' || :
|
||||
restorecon -R /usr/lib/portmaster/portmaster-core 2>/dev/null >&2 || :
|
||||
fi
|
||||
|
||||
echo "[ ] Initializing binary files"
|
||||
mv /usr/bin/portmaster /usr/lib/portmaster/portmaster
|
||||
ln -s /usr/lib/portmaster/portmaster /usr/bin/portmaster
|
||||
|
||||
chmod +x /usr/lib/portmaster/portmaster-core
|
||||
|
||||
echo "[ ] Enabling service"
|
||||
systemctl daemon-reload
|
||||
systemctl enable portmaster.service
|
||||
|
||||
echo "Please reboot your system"
|
||||
echo "[ ] Done. Please reboot your system"
|
||||
|
|
|
@ -1,10 +1,35 @@
|
|||
#!/bin/bash
|
||||
|
||||
echo "[ ] Post-Remove script [arg1='$1' arg2='$2']"
|
||||
|
||||
# DEB argument on upgrade - 'upgrade'; RPM - '1'
|
||||
if [ "$1" = "upgrade" ] || [ "$1" = "1" ] ; then
|
||||
echo "[ ] Post-Remove script: This is an upgrade."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
#
|
||||
# Remove selinux permissions for portmaster-core if we have semanage
|
||||
# available.
|
||||
# Remove selinux permissions for portmaster-core if we have semanage available.
|
||||
#
|
||||
if command -V semanage >/dev/null 2>&1; then
|
||||
echo "[ ] Removing SELinux permissions"
|
||||
semanage fcontext --delete $(realpath /usr/lib)'/portmaster/portmaster-core' || :
|
||||
restorecon -R /usr/lib/portmaster/portmaster-core 2>/dev/null >&2 || :
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "[ ] Stopping and disabling service"
|
||||
systemctl stop portmaster.service
|
||||
systemctl disable portmaster.service
|
||||
|
||||
echo "[ ] Removing files"
|
||||
# Remove binaries folder
|
||||
sudo rm -fr /usr/lib/portmaster
|
||||
# Remove data folder
|
||||
sudo rm -fr /var/lib/portmaster
|
||||
|
||||
# remove V1 migration flag (if exists)
|
||||
MIGRATED_FILE_FLAG="/opt/safing/portmaster/migrated.txt"
|
||||
if [ -e "$MIGRATED_FILE_FLAG" ]; then
|
||||
echo "[ ] Removing V1 migration flag"
|
||||
rm "$MIGRATED_FILE_FLAG"
|
||||
fi
|
||||
|
|
47
packaging/linux/readme.md
Normal file
47
packaging/linux/readme.md
Normal file
|
@ -0,0 +1,47 @@
|
|||
# Installation scripts order
|
||||
|
||||
Execution order of installation scripts (`preInstallScript, preRemoveScript, postInstallScript, postRemoveScript`) is different for DEB and RPM packages.
|
||||
**NOTE!** 'remove' scripts is using from old version!
|
||||
|
||||
## DEB scripts order
|
||||
|
||||
Useful link: https://wiki.debian.org/MaintainerScripts
|
||||
```
|
||||
DEB (apt) Install v2.2.2:
|
||||
[*] Before install (2.2.2 : deb : install)
|
||||
[*] After install (2.2.2 : deb : configure)
|
||||
|
||||
DEB (apt) Upgrade v1.1.1 -> v2.2.2:
|
||||
[*] Before remove (1.1.1 : deb : upgrade)
|
||||
[*] Before install (2.2.2 : deb : upgrade)
|
||||
[*] After remove (1.1.1 : deb : upgrade)
|
||||
[*] After install (2.2.2 : deb : configure)
|
||||
|
||||
DEB (apt) Remove:
|
||||
[*] Before remove (1.1.1 : deb : remove)
|
||||
[*] After remove (1.1.1 : deb : remove)
|
||||
```
|
||||
|
||||
## RPM scripts order
|
||||
|
||||
Useful link: https://docs.fedoraproject.org/en-US/packaging-guidelines/Scriptlets/
|
||||
|
||||
When scriptlets are called, they will be supplied with an argument.
|
||||
This argument, accessed via $1 (for shell scripts) is the number of packages of this name
|
||||
which will be left on the system when the action completes.
|
||||
|
||||
```
|
||||
RPM (dnf) install:
|
||||
[*] Before install (2.2.2 : rpm : 1)
|
||||
[*] After install (2.2.2 : rpm : 1)
|
||||
|
||||
RPM (dnf) upgrade:
|
||||
[*] Before install (2.2.2 : rpm : 2)
|
||||
[*] After install (2.2.2 : rpm : 2)
|
||||
[*] Before remove (1.1.1 : rpm : 1)
|
||||
[*] After remove (1.1.1 : rpm : 1)
|
||||
|
||||
RPM (dnf) remove:
|
||||
[*] Before remove (2.2.2 : rpm : 0)
|
||||
[*] After remove (2.2.2 : rpm : 0)
|
||||
```
|
|
@ -1,74 +1,313 @@
|
|||
# Tested with docker image 'abrarov/msvc-2022:latest'
|
||||
# sha256:f49435d194108cd56f173ad5bc6a27c70eed98b7e8cd54488f5acd85efbd51c9
|
||||
#------------------------------------------------------------------------------
|
||||
# Portmaster Windows Installer Generator
|
||||
#------------------------------------------------------------------------------
|
||||
# This script creates Windows installers (MSI and NSIS) for Portmaster application
|
||||
# by combining pre-compiled binaries and packaging them with Tauri.
|
||||
#
|
||||
# ## Workflow for creating Portmaster Windows installers:
|
||||
#
|
||||
# 1. Compile Core Binaries (Linux environment)
|
||||
# ```
|
||||
# earthly +release-prep
|
||||
# ```
|
||||
# This compiles and places files into the 'dist' folder with the required structure.
|
||||
# Note: Latest KEXT binaries and Intel data will be downloaded from https://updates.safing.io
|
||||
#
|
||||
# 2. Compile Windows-Specific Binaries (Windows environment)
|
||||
# Some files cannot be compiled by Earthly and require Windows.
|
||||
# - Compile 'portmaster-core.dll' from the /windows_core_dll folder
|
||||
# - Copy the compiled DLL to <project-root>/dist/downloaded/windows_amd64
|
||||
#
|
||||
# 3. Sign All Binaries (Windows environment)
|
||||
# ```
|
||||
# .\packaging\windows\sign_binaries_in_dist.ps1 -certSha1 <SHA1_of_the_certificate>
|
||||
# ```
|
||||
# This signs all binary files in the dist directory
|
||||
#
|
||||
# 4. Create Installers (Windows environment)
|
||||
# Note! You can run it from docker container (see example bellow).
|
||||
# ```
|
||||
# .\generate_windows_installers.ps1
|
||||
# ```
|
||||
# Installers will be placed in <project-root>/dist/windows_amd64
|
||||
#
|
||||
# 5. Sign Installers (Windows environment)
|
||||
# ```
|
||||
# .\packaging\windows\sign_binaries_in_dist.ps1 -certSha1 <SHA1_of_the_certificate>
|
||||
# ```
|
||||
# This signs the newly created installer files
|
||||
#
|
||||
#------------------------------------------------------------------------------
|
||||
# Running inside Docker container
|
||||
# Tested with docker image 'abrarov/msvc-2022:latest'
|
||||
# sha256:f49435d194108cd56f173ad5bc6a27c70eed98b7e8cd54488f5acd85efbd51c9
|
||||
#
|
||||
# Note! Ensure you switched Docker Desktop to use Windows containers.
|
||||
# Start powershell and cd to the root of the project.
|
||||
# Then run:
|
||||
# $path = Convert-Path . # Get the absolute path of the current directory
|
||||
# docker run -it --rm -v "${path}:C:/app" -w "C:/app" abrarov/msvc-2022 powershell -NoProfile -File C:/app/packaging/windows/generate_windows_installers.ps1
|
||||
#------------------------------------------------------------------------------
|
||||
#
|
||||
# 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
|
||||
#------------------------------------------------------------------------------
|
||||
param (
|
||||
[Alias('i')]
|
||||
[switch]$interactive,
|
||||
|
||||
# Run:
|
||||
# Start powershell and cd to the root of the project. Then run:
|
||||
# $path = Convert-Path . # Get the absolute path of the current directory
|
||||
# docker run -it --rm -v "${path}:C:/app" -w "C:/app" abrarov/msvc-2022 powershell -NoProfile -File C:/app/packaging/windows/generate_windows_installer.ps1
|
||||
[Alias('v')]
|
||||
[string]$version
|
||||
)
|
||||
|
||||
# Save the current directory
|
||||
$originalDirectory = Get-Location
|
||||
|
||||
$destinationDir = "desktop/tauri/src-tauri"
|
||||
$binaryDir = "$destinationDir/binary"
|
||||
$intelDir = "$destinationDir/intel"
|
||||
$targetDir = "$destinationDir/target/release"
|
||||
# <<<<<<<<<<<<<<<<<<<<<<< Functions <<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
# Make sure binary folder exists.
|
||||
if (-not (Test-Path -Path $binaryDir)) {
|
||||
New-Item -ItemType Directory -Path $binaryDir > $null
|
||||
# Function to copy a file, with fallback to an alternative location and detailed logging
|
||||
# Parameters:
|
||||
# $SourceDir - Primary directory to search for the file
|
||||
# $File - Name of the file to copy
|
||||
# $DestinationDir - Directory where the file will be copied to
|
||||
# $AlternateSourceDir - Fallback directory if file is not found in $SourceDir
|
||||
#
|
||||
# Behavior:
|
||||
# - Checks if the file exists in the primary source directory
|
||||
# - If not found and an alternate directory is provided, checks there
|
||||
# - In interactive mode, asks for confirmation before using the alternate source
|
||||
# - Logs details about the copied file (path, size, timestamp, version)
|
||||
# - Returns error and exits if file cannot be found or copied
|
||||
function Find-And-Copy-File {
|
||||
param (
|
||||
[string]$SourceDir,
|
||||
[string]$File,
|
||||
[string]$DestinationDir,
|
||||
[string[]]$AlternateSourceDirs # Changed from single string to array
|
||||
)
|
||||
$destinationPath = "$DestinationDir/$File"
|
||||
$fullSourcePath = if ($SourceDir) { "$SourceDir/$File" } else { "" }
|
||||
|
||||
if ($AlternateSourceDirs -and (-not $fullSourcePath -or -not (Test-Path -Path $fullSourcePath))) {
|
||||
# File doesn't exist, check in alternate folders
|
||||
$foundInAlternate = $false
|
||||
|
||||
foreach ($altDir in $AlternateSourceDirs) {
|
||||
$fallbackSourcePath = "$altDir/$File"
|
||||
if (Test-Path -Path $fallbackSourcePath) {
|
||||
if ($interactive -and $fullSourcePath) { # Do not prompt if the sourceDir is empty or "interactive" mode is not set
|
||||
$response = Read-Host " [?] The file '$File' found in fallback '$altDir' folder.`n Do you want to use it? (y/n)"
|
||||
if ($response -ne 'y' -and $response -ne 'Y') {
|
||||
continue # Try next alternate directory
|
||||
}
|
||||
}
|
||||
$fullSourcePath = $fallbackSourcePath
|
||||
$foundInAlternate = $true
|
||||
break # Found a usable file, stop searching
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $foundInAlternate) {
|
||||
$altDirsString = $AlternateSourceDirs -join "', '"
|
||||
Write-Error "Required file '$File' not found in: '$SourceDir', '$altDirsString'"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
# Print details about the file
|
||||
$fileInfo = Get-Item -Path $fullSourcePath
|
||||
$output = "{0,-22}: {1,-29} -> {2,-38} [{3,-20} {4,18}{5}]" -f
|
||||
$File,
|
||||
$(Split-Path -Path $fullSourcePath -Parent),
|
||||
$(Split-Path -Path $destinationPath -Parent),
|
||||
"$($fileInfo.LastAccessTime.ToString("yyyy-MM-dd HH:mm:ss"));",
|
||||
"$($fileInfo.Length) bytes",
|
||||
$(if ($fileInfo.VersionInfo.FileVersion) { "; v$($fileInfo.VersionInfo.FileVersion)" } else { "" })
|
||||
Write-Output "$output"
|
||||
|
||||
# Create destination directory if not exists
|
||||
if (-not (Test-Path -Path $DestinationDir)) {
|
||||
New-Item -ItemType Directory -Path $DestinationDir -ErrorAction Stop > $null
|
||||
}
|
||||
# Copy the file
|
||||
Copy-Item -Force -Path "${fullSourcePath}" -Destination "${destinationPath}" -ErrorAction Stop
|
||||
} catch {
|
||||
Write-Error "Failed to copy file from '$fullSourcePath' to '$destinationPath'.`nError: $_"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
Write-Output "Copying binary files"
|
||||
Copy-Item -Force -Path "dist/download/windows_amd64/portmaster-core.exe" -Destination "$binaryDir/portmaster-core.exe"
|
||||
Copy-Item -Force -Path "dist/download/windows_amd64/portmaster-kext.sys" -Destination "$binaryDir/portmaster-kext.sys"
|
||||
Copy-Item -Force -Path "dist/download/windows_amd64/portmaster-kext.dll" -Destination "$binaryDir/portmaster-kext.dll"
|
||||
Copy-Item -Force -Path "dist/binary/all/portmaster.zip" -Destination "$binaryDir/portmaster.zip"
|
||||
Copy-Item -Force -Path "dist/binary/all/assets.zip" -Destination "$binaryDir/assets.zip"
|
||||
|
||||
# Make sure target folder exists.
|
||||
if (-not (Test-Path -Path $targetDir)) {
|
||||
New-Item -ItemType Directory -Path $targetDir > $null
|
||||
# Function to set and restore Cargo.toml version
|
||||
function Set-CargoVersion {
|
||||
param ([string]$Version)
|
||||
if (-not (Test-Path "Cargo.toml.bak")) {
|
||||
Copy-Item "Cargo.toml" "Cargo.toml.bak" -Force
|
||||
}
|
||||
# Update the version in Cargo.toml.
|
||||
# This will allow the Tauri CLI to set the correct filename for the installer.
|
||||
# NOTE: This works only when the version is not explicitly defined in tauri.conf.json5.
|
||||
(Get-Content "Cargo.toml" -Raw) -replace '(\[package\][^\[]*?)version\s*=\s*"[^"]+"', ('$1version = "' + $Version + '"') | Set-Content "Cargo.toml"
|
||||
}
|
||||
Copy-Item -Force -Path "dist/binary/windows_amd64/portmaster.exe" -Destination "$targetDir/portmaster.exe"
|
||||
|
||||
# Make sure intel folder exists.
|
||||
if (-not (Test-Path -Path $intelDir)) {
|
||||
New-Item -ItemType Directory -Path $intelDir > $null
|
||||
function Restore-CargoVersion {
|
||||
if (Test-Path "Cargo.toml.bak") {
|
||||
Copy-Item "Cargo.toml.bak" "Cargo.toml" -Force
|
||||
Remove-Item "Cargo.toml.bak" -Force
|
||||
}
|
||||
}
|
||||
|
||||
Write-Output "Copying intel files"
|
||||
Copy-Item -Force -Path "dist/intel/*" -Destination "$intelDir/"
|
||||
function Get-GitTagVersion {
|
||||
# Check if running in Docker and configure Git accordingly
|
||||
if ($env:ComputerName -like "*container*" -or $env:USERNAME -eq "ContainerAdministrator") {
|
||||
$currentDir = (Get-Location).Path
|
||||
git config --global --add safe.directory $currentDir
|
||||
}
|
||||
|
||||
# Try to get exact tag pointing to current commit
|
||||
$version = $(git tag --points-at 2>$null)
|
||||
# If no tag points to current commit, use most recent tag
|
||||
if ([string]::IsNullOrEmpty($version)) {
|
||||
$devVersion = $(git describe --tags --first-parent --abbrev=0 2>$null)
|
||||
if (-not [string]::IsNullOrEmpty($devVersion)) {
|
||||
$version = "${devVersion}"
|
||||
}
|
||||
}
|
||||
$version = $version -replace '^v', ''
|
||||
return $version
|
||||
}
|
||||
# >>>>>>>>>>>>>>>>>>>>>>> End Functions >>>>>>>>>>>>>>>>>>>>>>>>
|
||||
|
||||
# Set-Location relative to the script location "../.." (root of the project). So that the script can be run from any location.
|
||||
Set-Location -Path (Join-Path -Path $PSScriptRoot -ChildPath "../..")
|
||||
try {
|
||||
# CONSTANTS
|
||||
$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
|
||||
|
||||
# Copying BINARY FILES
|
||||
Write-Output "`n[+] Copying binary files:"
|
||||
$filesToCopy = @(
|
||||
@{Folder="dist/binary/windows_amd64"; File="portmaster-kext.sys"; Destination=$binaryDir; AlternateSourceDirs=@("dist/downloaded/windows_amd64", "dist")},
|
||||
@{Folder="dist/binary/windows_amd64"; File="portmaster-core.dll"; Destination=$binaryDir; AlternateSourceDirs=@("dist/downloaded/windows_amd64", "dist")},
|
||||
@{Folder="dist/binary/windows_amd64"; File="portmaster-core.exe"; Destination=$binaryDir; AlternateSourceDirs=@("dist")},
|
||||
@{Folder="dist/binary/windows_amd64"; File="WebView2Loader.dll"; Destination=$binaryDir; AlternateSourceDirs=@("dist")},
|
||||
@{Folder="dist/binary/all"; File="portmaster.zip"; Destination=$binaryDir; AlternateSourceDirs=@("dist")},
|
||||
@{Folder="dist/binary/all"; File="assets.zip"; Destination=$binaryDir; AlternateSourceDirs=@("dist")},
|
||||
@{Folder="dist/binary/windows_amd64"; File="portmaster.exe"; Destination=$targetDir; AlternateSourceDirs=@("dist")}
|
||||
)
|
||||
foreach ($file in $filesToCopy) {
|
||||
Find-And-Copy-File -SourceDir $file.Folder -File $file.File -DestinationDir $file.Destination -AlternateSourceDirs $file.AlternateSourceDirs
|
||||
}
|
||||
|
||||
# Copying INTEL FILES
|
||||
Write-Output "`n[+] Copying intel files"
|
||||
if (-not (Test-Path -Path $intelDir)) {
|
||||
New-Item -ItemType Directory -Path $intelDir -ErrorAction Stop > $null
|
||||
}
|
||||
Copy-Item -Force -Path "dist/intel/*" -Destination "$intelDir/" -ErrorAction Stop
|
||||
} catch {
|
||||
Set-Location $originalDirectory
|
||||
Write-Error "[!] Failed! Error: $_"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$VERSION_GIT_TAG = Get-GitTagVersion
|
||||
|
||||
# Check versions of UI and Core binaries
|
||||
$VERSION_UI = (Get-Item "$targetDir/portmaster.exe").VersionInfo.FileVersion
|
||||
$VERSION_CORE = (& "$binaryDir/portmaster-core.exe" version | Select-String -Pattern "Portmaster\s+(\d+\.\d+\.\d+)" | ForEach-Object { $_.Matches.Groups[1].Value })
|
||||
$VERSION_KEXT = (Get-Item "$binaryDir/portmaster-kext.sys").VersionInfo.FileVersion
|
||||
Write-Output "`n[i] VERSIONS INFO:"
|
||||
Write-Output " VERSION_GIT_TAG : $VERSION_GIT_TAG"
|
||||
Write-Output " VERSION_CORE : $VERSION_CORE"
|
||||
Write-Output " VERSION_UI : $VERSION_UI"
|
||||
Write-Output " VERSION_KEXT : $VERSION_KEXT"
|
||||
if ($VERSION_UI -ne $VERSION_CORE -or $VERSION_CORE -ne $VERSION_GIT_TAG) {
|
||||
Write-Warning "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
Write-Warning "Version mismatch between UI($VERSION_UI), Core($VERSION_CORE) and GitTag($VERSION_GIT_TAG)!"
|
||||
Write-Warning "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
if ($interactive) {
|
||||
$response = Read-Host "[?] Continue anyway? (y/n)"
|
||||
if ($response -ne 'y' -and $response -ne 'Y') {
|
||||
Write-Error "Cancelled. Version mismatch between UI and Core binaries."
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
# Determine which version to use for building
|
||||
if ($version) {
|
||||
Write-Output "`n[i] Using explicitly provided version ($version) for installer file name`n"
|
||||
$VERSION_TO_USE = $version
|
||||
} else {
|
||||
Write-Output "`n[i] Using Core version version ($VERSION_CORE) for installer file name`n"
|
||||
$VERSION_TO_USE = $VERSION_CORE
|
||||
}
|
||||
|
||||
Set-Location $destinationDir
|
||||
try {
|
||||
# Ensure Rust toolchain is installed
|
||||
if (-not (Get-Command cargo -ErrorAction SilentlyContinue)) {
|
||||
Write-Output "[+] Installing rust toolchain..."
|
||||
Start-BitsTransfer -Source "https://win.rustup.rs/x86_64" -Destination "rustup.exe"
|
||||
./rustup.exe install --no-self-update stable
|
||||
$env:PATH += ";C:\Users\ContainerAdministrator\.rustup\toolchains\stable-x86_64-pc-windows-msvc\bin\"
|
||||
}
|
||||
|
||||
if (-not (Get-Command cargo -ErrorAction SilentlyContinue)) {
|
||||
Write-Output "Installing rust toolchain..."
|
||||
Invoke-WebRequest -Uri https://win.rustup.rs/x86_64 -OutFile rustup.exe
|
||||
./rustup.exe install stable
|
||||
$env:PATH += ";C:\Users\ContainerAdministrator\.rustup\toolchains\stable-x86_64-pc-windows-msvc\bin\"
|
||||
} else {
|
||||
Write-Output "'cargo' command is already available"
|
||||
# Ensure Tauri CLI is available
|
||||
$cargoTauriCommand = "cargo-tauri.exe"
|
||||
if (-not (Get-Command $cargoTauriCommand -ErrorAction SilentlyContinue)) {
|
||||
if (-not (Test-Path "./tauri-cli/cargo-tauri.exe")) {
|
||||
Write-Output "[+] Tauri CLI not found. Downloading tauri-cli"
|
||||
Start-BitsTransfer -Source "https://github.com/tauri-apps/tauri/releases/download/tauri-cli-v2.2.7/cargo-tauri-x86_64-pc-windows-msvc.zip" -Destination "tauri-cli.zip"
|
||||
Expand-Archive -Force tauri-cli.zip
|
||||
}
|
||||
if (-not (Test-Path "./tauri-cli/cargo-tauri.exe")) {
|
||||
Write-Error "Tauri CLI not found. Download failed."
|
||||
exit 1
|
||||
}
|
||||
$cargoTauriCommand = "./tauri-cli/cargo-tauri.exe"
|
||||
}
|
||||
|
||||
Write-Output "[i] Tools versions info:"
|
||||
Write-Output " Tauri CLI: $((& $cargoTauriCommand -V | Out-String).Trim().Replace("`r`n", " "))"
|
||||
Write-Output " Rust : $((rustc -V | Out-String).Trim().Replace("`r`n", " ")); $((cargo -V | Out-String).Trim().Replace("`r`n", " "))"
|
||||
Write-Output ""
|
||||
|
||||
# Building Tauri app bundle
|
||||
try {
|
||||
Write-Output "[+] Building Tauri app bundle with version $VERSION_TO_USE"
|
||||
Set-CargoVersion -Version $VERSION_TO_USE
|
||||
& $cargoTauriCommand bundle
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Tauri bundle command failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Error "[!] Bundle failed: $_"
|
||||
exit 1
|
||||
}
|
||||
finally {
|
||||
Restore-CargoVersion
|
||||
}
|
||||
|
||||
Write-Output "[+] Copying generated bundles"
|
||||
$installerDist = "..\..\..\dist\windows_amd64\"
|
||||
if (-not (Test-Path -Path $installerDist)) {
|
||||
New-Item -ItemType Directory -Path $installerDist -ErrorAction Stop > $null
|
||||
}
|
||||
#Copy-Item -Path ".\target\release\bundle\msi\*" -Destination $installerDist -ErrorAction Stop
|
||||
Copy-Item -Path ".\target\release\bundle\nsis\*" -Destination $installerDist -ErrorAction Stop
|
||||
|
||||
Write-Output "[i] Done."
|
||||
Write-Output " Installer files are available in: $(Resolve-Path $installerDist)"
|
||||
} catch {
|
||||
Write-Error "[!] Failed! Error: $_"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Output "Downloading tauri-cli"
|
||||
|
||||
Invoke-WebRequest -Uri https://github.com/tauri-apps/tauri/releases/download/tauri-cli-v2.1.0/cargo-tauri-x86_64-pc-windows-msvc.zip -OutFile tauri-cli.zip
|
||||
Expand-Archive -Force tauri-cli.zip
|
||||
./tauri-cli/cargo-tauri.exe bundle
|
||||
|
||||
|
||||
Write-Output "Copying generated bundles"
|
||||
$installerDist = "..\..\..\dist\windows_amd64\"
|
||||
# Make sure distination folder exists.
|
||||
if (-not (Test-Path -Path $installerDist)) {
|
||||
New-Item -ItemType Directory -Path $installerDist > $null
|
||||
}
|
||||
|
||||
Copy-Item -Path ".\target\release\bundle\msi\*" -Destination $installerDist
|
||||
Copy-Item -Path ".\target\release\bundle\nsis\*" -Destination $installerDist
|
||||
|
||||
|
||||
# Restore the original directory
|
||||
Set-Location $originalDirectory
|
||||
|
||||
finally {
|
||||
# Restore the original directory if not already done
|
||||
Set-Location $originalDirectory
|
||||
}
|
179
packaging/windows/sign_binaries_in_dist.ps1
Normal file
179
packaging/windows/sign_binaries_in_dist.ps1
Normal file
|
@ -0,0 +1,179 @@
|
|||
param (
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$certSha1,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$timestampServer = "http://timestamp.digicert.com"
|
||||
)
|
||||
|
||||
function Show-Help {
|
||||
Write-Host "Usage: sign_binaries_in_dist.ps1 -certSha1 <CERT_SHA1> [-timestampServer <TIMESTAMP_SERVER>]"
|
||||
Write-Host ""
|
||||
Write-Host "This script signs all binary files located under the '<project root>\dist\' directory recursively."
|
||||
Write-Host "Which should be done before creating the Portmaster installer."
|
||||
Write-Host ""
|
||||
Write-Host "Arguments:"
|
||||
Write-Host " -certSha1 The SHA1 hash of the certificate to use for signing (code signing certificate)."
|
||||
Write-Host " -timestampServer The timestamp server URL to use (optional). Default is http://timestamp.digicert.com."
|
||||
Write-Host ""
|
||||
Write-Host "Example:"
|
||||
Write-Host " .\sign_binaries_in_dist.ps1 -certSha1 ABCDEF1234567890ABCDEF1234567890ABCDEF12"
|
||||
}
|
||||
|
||||
# Show help if no certificate SHA1 provided or help flag used
|
||||
if (-not $certSha1 -or ($args -contains "-h") -or ($args -contains "-help") -or ($args -contains "/h")) {
|
||||
Show-Help
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Find signtool.exe - simplified approach
|
||||
function Find-SignTool {
|
||||
# First try the PATH
|
||||
$signtool = Get-Command signtool.exe -ErrorAction SilentlyContinue
|
||||
if ($signtool) { return $signtool }
|
||||
|
||||
Write-Host "[+] signtool.exe not found in PATH. Searching in common locations..."
|
||||
|
||||
# Common locations for signtool
|
||||
$commonLocations = @(
|
||||
# Windows SDK paths
|
||||
"${env:ProgramFiles(x86)}\Windows Kits\10\bin\*\x64\signtool.exe",
|
||||
"${env:ProgramFiles(x86)}\Windows Kits\10\bin\*\x86\signtool.exe",
|
||||
|
||||
# Visual Studio paths via vswhere
|
||||
(& "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.Component.MSBuild -find "**/signtool.exe" -ErrorAction SilentlyContinue)
|
||||
)
|
||||
|
||||
foreach ($location in $commonLocations) {
|
||||
$tools = Get-ChildItem -Path $location -ErrorAction SilentlyContinue |
|
||||
Sort-Object -Property FullName -Descending
|
||||
if ($tools -and $tools.Count -gt 0) {
|
||||
return $tools[0] # Return the first match
|
||||
}
|
||||
}
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
function Get-SignatureInfo {
|
||||
param(
|
||||
[string]$filePath
|
||||
)
|
||||
# Get the raw output from signtool
|
||||
$rawOutput = & $signtool verify /pa /v $filePath 2>&1
|
||||
|
||||
# Filter output to exclude everything after the timestamp line
|
||||
$filteredOutput = @()
|
||||
foreach ($line in $rawOutput) {
|
||||
if ($line -match "The signature is timestamped:") {
|
||||
break
|
||||
}
|
||||
$filteredOutput += $line
|
||||
}
|
||||
# Extract last subject in the signing chain - it's typically the last "Issued to:" entry
|
||||
$lastSubject = ($filteredOutput | Select-String -Pattern "Issued to: (.*)$" | Select-Object -Last 1 | ForEach-Object { $_.Matches.Groups[1].Value })
|
||||
# Create signature info object
|
||||
$signInfo = @{
|
||||
"IsSigned" = $LASTEXITCODE -eq 0
|
||||
"Subject" = ($filteredOutput | Select-String -Pattern "Issued to: (.*)$" | ForEach-Object { $_.Matches.Groups[1].Value }) -join ", "
|
||||
"Issuer" = ($filteredOutput | Select-String -Pattern "Issued by: (.*)$" | ForEach-Object { $_.Matches.Groups[1].Value }) -join ", "
|
||||
"ExpirationDate" = ($filteredOutput | Select-String -Pattern "Expires: (.*)$" | ForEach-Object { $_.Matches.Groups[1].Value }) -join ", "
|
||||
"SubjectLast" = $lastSubject
|
||||
"SignedBySameCert" = $false
|
||||
}
|
||||
|
||||
# Check if signed by our certificate
|
||||
$null = & $signtool verify /pa /sha1 $certSha1 $filePath 2>&1
|
||||
$signInfo.SignedBySameCert = $LASTEXITCODE -eq 0
|
||||
|
||||
return $signInfo
|
||||
}
|
||||
|
||||
# Find dist directory relative to script location
|
||||
$distDir = Join-Path $PSScriptRoot "../../dist"
|
||||
if (-not (Test-Path -Path $distDir)) {
|
||||
Write-Host "The directory '$distDir' does not exist." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
$distDir = Resolve-Path (Join-Path $PSScriptRoot "../../dist") # normalize path
|
||||
|
||||
# Find signtool.exe
|
||||
$signtool = Find-SignTool
|
||||
if (-not $signtool) {
|
||||
Write-Host "signtool.exe not found in any standard location." -ForegroundColor Red
|
||||
Write-Host "Please install one of the following:" -ForegroundColor Yellow
|
||||
Write-Host "- Windows SDK" -ForegroundColor Yellow
|
||||
Write-Host "- Visual Studio with the 'Desktop development with C++' workload" -ForegroundColor Yellow
|
||||
Write-Host "- Visual Studio Build Tools with the 'Desktop development with C++' workload" -ForegroundColor Yellow
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "[i] Using signtool: $($signtool)"
|
||||
|
||||
# Sign all binary files in the dist directory
|
||||
try {
|
||||
# Define extensions for files that should be signed
|
||||
$binaryExtensions = @('.exe', '.dll', '.sys', '.msi')
|
||||
|
||||
# Get all files with binary extensions
|
||||
$files = Get-ChildItem -Path $distDir -Recurse -File | Where-Object {
|
||||
$extension = [System.IO.Path]::GetExtension($_.Name).ToLower()
|
||||
$binaryExtensions -contains $extension
|
||||
}
|
||||
|
||||
$totalFiles = $files.Count
|
||||
$signedFiles = 0
|
||||
$alreadySignedFiles = 0
|
||||
$wrongCertFiles = 0
|
||||
$filesToSign = @()
|
||||
|
||||
Write-Host "[+] Found $totalFiles binary files to process" -ForegroundColor Green
|
||||
foreach ($file in $files) {
|
||||
$relativeFileName = $file.FullName.Replace("$distDir\", "")
|
||||
# Get signature information
|
||||
$signInfo = Get-SignatureInfo -filePath $file.FullName
|
||||
|
||||
if ($signInfo.IsSigned) {
|
||||
if ($signInfo.SignedBySameCert) {
|
||||
Write-Host -NoNewline " [signed OK ]" -ForegroundColor Green
|
||||
Write-Host -NoNewline " $($relativeFileName)" -ForegroundColor Blue
|
||||
Write-Host "`t: signed by our certificate"
|
||||
$alreadySignedFiles++
|
||||
} else {
|
||||
Write-Host -NoNewline " [different ]" -ForegroundColor Yellow
|
||||
Write-Host -NoNewline " $($relativeFileName)" -ForegroundColor Blue
|
||||
Write-Host "`t: signed by different certificate [$($signInfo.SubjectLast)]"
|
||||
$wrongCertFiles++
|
||||
}
|
||||
} else {
|
||||
Write-Host -NoNewline " [NOT signed]" -ForegroundColor Red
|
||||
Write-Host -NoNewline " $($relativeFileName)" -ForegroundColor Blue
|
||||
Write-Host "`t: not signed"
|
||||
$filesToSign += $file.FullName
|
||||
}
|
||||
}
|
||||
|
||||
# Batch sign files
|
||||
if ($filesToSign.Count -gt 0) {
|
||||
Write-Host "`n[+] Signing $($filesToSign.Count) files in batch..." -ForegroundColor Green
|
||||
|
||||
& $signtool sign /tr $timestampServer /td sha256 /fd sha256 /sha1 $certSha1 /v $filesToSign
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "Failed to sign files!" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
$signedFiles = $filesToSign.Count
|
||||
} else {
|
||||
Write-Host "`n[+] No files need signing." -ForegroundColor Green
|
||||
}
|
||||
|
||||
Write-Host "`n[+] Summary:" -ForegroundColor Green
|
||||
Write-Host " - Total binary files found: $totalFiles"
|
||||
Write-Host " - Files already signed with our certificate: $alreadySignedFiles"
|
||||
Write-Host " - Files signed with different certificate: $wrongCertFiles"
|
||||
Write-Host " - Files newly signed: $signedFiles"
|
||||
} catch {
|
||||
Write-Host "An error occurred: $_" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
|
@ -35,7 +35,7 @@ func (sc *ServiceConfig) Init() error {
|
|||
if sc.BinDir == "" {
|
||||
exeDir, err := getCurrentBinaryFolder() // Default: C:/Program Files/Portmaster
|
||||
if err != nil {
|
||||
return fmt.Errorf("derive bin dir from runnning exe: %w", err)
|
||||
return fmt.Errorf("derive bin dir from running exe: %w", err)
|
||||
}
|
||||
sc.BinDir = exeDir
|
||||
}
|
||||
|
|
|
@ -56,15 +56,8 @@ func (ub *updateBroadcaster) AvailableUpdate() *updates.Artifact {
|
|||
// Get artifact.
|
||||
artifact, err := module.instance.IntelUpdates().GetFile(ub.dbName)
|
||||
if err != nil {
|
||||
// Check if the geoip database is included in the binary index instead.
|
||||
// TODO: Remove when intelhub builds the geoip database.
|
||||
if artifact2, err2 := module.instance.BinaryUpdates().GetFile(ub.dbName); err2 == nil {
|
||||
artifact = artifact2
|
||||
err = nil
|
||||
} else {
|
||||
log.Warningf("geoip: failed to get geoip update: %s", err)
|
||||
return nil
|
||||
}
|
||||
log.Warningf("geoip: failed to get geoip update: %s", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Return artifact if not yet initialized.
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/safing/portmaster/base/info"
|
||||
"github.com/safing/portmaster/base/log"
|
||||
"github.com/safing/portmaster/base/notifications"
|
||||
"github.com/safing/portmaster/base/utils"
|
||||
"github.com/safing/portmaster/service/mgr"
|
||||
)
|
||||
|
||||
|
@ -171,6 +172,12 @@ func New(instance instance, name string, cfg Config) (*Updater, error) {
|
|||
return nil, fmt.Errorf("config is invalid: %w", err)
|
||||
}
|
||||
|
||||
// Make sure main dir exists.
|
||||
err := utils.EnsureDirectory(module.cfg.Directory, utils.PublicReadExecPermission)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create update target directory: %s", module.cfg.DownloadDirectory)
|
||||
}
|
||||
|
||||
// Create Workers.
|
||||
module.updateCheckWorkerMgr = m.NewWorkerMgr("update checker", module.updateCheckWorker, nil)
|
||||
module.upgradeWorkerMgr = m.NewWorkerMgr("upgrader", module.upgradeWorker, nil)
|
||||
|
|
Loading…
Add table
Reference in a new issue