mirror of
https://github.com/wailsapp/wails.git
synced 2026-03-18 00:19:58 +01:00
I have successfully implemented the "Start At Login" feature for Wails v3, addressing all the major concerns raised in PR #3910. Here's what was accomplished: ### ✅ **Core Implementation** 1. **Added StartAtLogin option** to `application.Options` struct 2. **Implemented platform-specific methods** for all three platforms: - **macOS**: Uses AppleScript with proper escaping to prevent injection attacks - **Windows**: Uses Windows Registry with restrictive permissions - **Linux**: Uses XDG autostart specification with .desktop files 3. **Added public API methods**: - `SetStartAtLogin(enabled bool) error` - Enable/disable start at login - `StartsAtLogin() (bool, error)` - Check current status ### ✅ **Security Improvements** (addressing PR comments) 1. **Path validation and sanitization** across all platforms 2. **AppleScript injection protection** on macOS with proper escaping 3. **Registry permissions** restricted to necessary access on Windows 4. **Executable path validation** with symlink resolution 5. **Input sanitization** for application names and paths ### ✅ **Error Handling & Documentation** 1. **Comprehensive error handling** with descriptive error messages 2. **Complete API documentation** with platform-specific behavior notes 3. **macOS Info.plist requirement** documented (NSAppleEventsUsageDescription) 4. **Cross-platform compatibility** notes and troubleshooting ### ✅ **Example & Testing** 1. **Working example application** demonstrating usage 2. **Comprehensive README** with platform-specific requirements 3. **Runtime toggling capability** implemented 4. **Compilation verified** - the implementation builds successfully ### 🔧 **Technical Details** - **macOS**: Uses Bundle information and AppleScript with security hardening - **Windows**: Uses HKEY_CURRENT_USER registry with KEY_SET_VALUE/KEY_QUERY_VALUE permissions - **Linux**: Creates XDG-compliant .desktop files in ~/.config/autostart/ ### 📋 **Key Features** - ✅ Cross-platform support (macOS, Windows, Linux) - ✅ Runtime configuration via public API - ✅ Application startup configuration via Options - ✅ Security hardening against injection attacks - ✅ Proper error handling and validation - ✅ Complete documentation and examples The implementation is now ready for testing and can be integrated into Wails v3. All major security concerns from the original PR have been addressed, and the feature includes proper documentation for developers.
228 lines
8.7 KiB
Go
228 lines
8.7 KiB
Go
package application
|
|
|
|
import (
|
|
"io/fs"
|
|
"log/slog"
|
|
"net/http"
|
|
|
|
"github.com/wailsapp/wails/v3/internal/assetserver"
|
|
)
|
|
|
|
// Options contains the options for the application
|
|
type Options struct {
|
|
// Name is the name of the application (used in the default about box)
|
|
Name string
|
|
|
|
// Description is the description of the application (used in the default about box)
|
|
Description string
|
|
|
|
// Icon is the icon of the application (used in the default about box)
|
|
Icon []byte
|
|
|
|
// Mac is the Mac specific configuration for Mac builds
|
|
Mac MacOptions
|
|
|
|
// Windows is the Windows specific configuration for Windows builds
|
|
Windows WindowsOptions
|
|
|
|
// Linux is the Linux specific configuration for Linux builds
|
|
Linux LinuxOptions
|
|
|
|
// Services allows you to bind Go methods to the frontend.
|
|
Services []Service
|
|
|
|
// MarshalError will be called if non-nil
|
|
// to marshal to JSON the error values returned by service methods.
|
|
//
|
|
// MarshalError is not allowed to fail,
|
|
// but it may return a nil slice to fall back
|
|
// to the default error handling mechanism.
|
|
//
|
|
// If the returned slice is not nil, it must contain valid JSON.
|
|
MarshalError func(error) []byte
|
|
|
|
// BindAliases allows you to specify alias IDs for your bound methods.
|
|
// Example: `BindAliases: map[uint32]uint32{1: 1411160069}` states that alias ID 1 maps to the Go method with ID 1411160069.
|
|
BindAliases map[uint32]uint32
|
|
|
|
// Logger is a slog.Logger instance used for logging Wails system messages (not application messages).
|
|
// If not defined, a default logger is used.
|
|
Logger *slog.Logger
|
|
|
|
// LogLevel defines the log level of the Wails system logger.
|
|
LogLevel slog.Level
|
|
|
|
// Assets are the application assets to be used.
|
|
Assets AssetOptions
|
|
|
|
// Flags are key value pairs that are available to the frontend.
|
|
// This is also used by Wails to provide information to the frontend.
|
|
Flags map[string]any
|
|
|
|
// PanicHandler is called when a panic occurs
|
|
PanicHandler func(*PanicDetails)
|
|
|
|
// DisableDefaultSignalHandler disables the default signal handler
|
|
DisableDefaultSignalHandler bool
|
|
|
|
// KeyBindings is a map of key bindings to functions
|
|
KeyBindings map[string]func(window *WebviewWindow)
|
|
|
|
// OnShutdown is called when the application is about to terminate.
|
|
// This is useful for cleanup tasks.
|
|
// The shutdown process blocks until this function returns.
|
|
OnShutdown func()
|
|
|
|
// PostShutdown is called after the application
|
|
// has finished shutting down, just before process termination.
|
|
// This is useful for testing and logging purposes
|
|
// on platforms where the Run() method does not return.
|
|
// When PostShutdown is called, the application instance is not usable anymore.
|
|
// The shutdown process blocks until this function returns.
|
|
PostShutdown func()
|
|
|
|
// ShouldQuit is a function that is called when the user tries to quit the application.
|
|
// If the function returns true, the application will quit.
|
|
// If the function returns false, the application will not quit.
|
|
ShouldQuit func() bool
|
|
|
|
// RawMessageHandler is called when the frontend sends a raw message.
|
|
// This is useful for implementing custom frontend-to-backend communication.
|
|
RawMessageHandler func(window Window, message string)
|
|
|
|
// WarningHandler is called when a warning occurs
|
|
WarningHandler func(string)
|
|
|
|
// ErrorHandler is called when an error occurs
|
|
ErrorHandler func(err error)
|
|
|
|
// File extensions associated with the application
|
|
// Example: [".txt", ".md"]
|
|
// The '.' is required
|
|
FileAssociations []string
|
|
|
|
// SingleInstance options for single instance functionality
|
|
SingleInstance *SingleInstanceOptions
|
|
|
|
// StartAtLogin configures the application to start automatically when the user logs in
|
|
StartAtLogin bool
|
|
}
|
|
|
|
// AssetOptions defines the configuration of the AssetServer.
|
|
type AssetOptions struct {
|
|
// Handler which serves all the content to the WebView.
|
|
Handler http.Handler
|
|
|
|
// Middleware is a HTTP Middleware which allows to hook into the AssetServer request chain. It allows to skip the default
|
|
// request handler dynamically, e.g. implement specialized Routing etc.
|
|
// The Middleware is called to build a new `http.Handler` used by the AssetSever and it also receives the default
|
|
// handler used by the AssetServer as an argument.
|
|
//
|
|
// This middleware injects itself before any of Wails internal middlewares.
|
|
//
|
|
// If not defined, the default AssetServer request chain is executed.
|
|
//
|
|
// Multiple Middlewares can be chained together with:
|
|
// ChainMiddleware(middleware ...Middleware) Middleware
|
|
Middleware Middleware
|
|
|
|
// DisableLogging disables logging of the AssetServer. By default, the AssetServer logs every request.
|
|
DisableLogging bool
|
|
}
|
|
|
|
// Middleware defines HTTP middleware that can be applied to the AssetServer.
|
|
// The handler passed as next is the next handler in the chain. One can decide to call the next handler
|
|
// or implement a specialized handling.
|
|
type Middleware func(next http.Handler) http.Handler
|
|
|
|
// ChainMiddleware allows chaining multiple middlewares to one middleware.
|
|
func ChainMiddleware(middleware ...Middleware) Middleware {
|
|
return func(h http.Handler) http.Handler {
|
|
for i := len(middleware) - 1; i >= 0; i-- {
|
|
h = middleware[i](h)
|
|
}
|
|
return h
|
|
}
|
|
}
|
|
|
|
// AssetFileServerFS returns a http handler which serves the assets from the fs.FS.
|
|
// If an external devserver has been provided 'FRONTEND_DEVSERVER_URL' the files are being served
|
|
// from the external server, ignoring the `assets`.
|
|
func AssetFileServerFS(assets fs.FS) http.Handler {
|
|
return assetserver.NewAssetFileServer(assets)
|
|
}
|
|
|
|
// BundledAssetFileServer returns a http handler which serves the assets from the fs.FS.
|
|
// If an external devserver has been provided 'FRONTEND_DEVSERVER_URL' the files are being served
|
|
// from the external server, ignoring the `assets`.
|
|
// It also serves the compiled runtime.js file at `/wails/runtime.js`.
|
|
// It will provide the production runtime.js file from the embedded assets if the `production` tag is used.
|
|
func BundledAssetFileServer(assets fs.FS) http.Handler {
|
|
return assetserver.NewBundledAssetFileServer(assets)
|
|
}
|
|
|
|
/******** Mac Options ********/
|
|
|
|
// ActivationPolicy is the activation policy for the application.
|
|
type ActivationPolicy int
|
|
|
|
const (
|
|
// ActivationPolicyRegular is used for applications that have a user interface,
|
|
ActivationPolicyRegular ActivationPolicy = iota
|
|
// ActivationPolicyAccessory is used for applications that do not have a main window,
|
|
// such as system tray applications or background applications.
|
|
ActivationPolicyAccessory
|
|
ActivationPolicyProhibited
|
|
)
|
|
|
|
// MacOptions contains options for macOS applications.
|
|
type MacOptions struct {
|
|
// ActivationPolicy is the activation policy for the application. Defaults to
|
|
// applicationActivationPolicyRegular.
|
|
ActivationPolicy ActivationPolicy
|
|
// If set to true, the application will terminate when the last window is closed.
|
|
ApplicationShouldTerminateAfterLastWindowClosed bool
|
|
}
|
|
|
|
/****** Windows Options *******/
|
|
|
|
// WindowsOptions contains options for Windows applications.
|
|
type WindowsOptions struct {
|
|
|
|
// Window class name
|
|
// Default: WailsWebviewWindow
|
|
WndClass string
|
|
|
|
// WndProcInterceptor is a function that will be called for every message sent in the application.
|
|
// Use this to hook into the main message loop. This is useful for handling custom window messages.
|
|
// If `shouldReturn` is `true` then `returnCode` will be returned by the main message loop.
|
|
// If `shouldReturn` is `false` then returnCode will be ignored and the message will be processed by the main message loop.
|
|
WndProcInterceptor func(hwnd uintptr, msg uint32, wParam, lParam uintptr) (returnCode uintptr, shouldReturn bool)
|
|
|
|
// DisableQuitOnLastWindowClosed disables the auto quit of the application if the last window has been closed.
|
|
DisableQuitOnLastWindowClosed bool
|
|
|
|
// Path where the WebView2 stores the user data. If empty %APPDATA%\[BinaryName.exe] will be used.
|
|
// If the path is not valid, a messagebox will be displayed with the error and the app will exit with error code.
|
|
WebviewUserDataPath string
|
|
|
|
// Path to the directory with WebView2 executables. If empty WebView2 installed in the system will be used.
|
|
WebviewBrowserPath string
|
|
}
|
|
|
|
/********* Linux Options *********/
|
|
|
|
// LinuxOptions contains options for Linux applications.
|
|
type LinuxOptions struct {
|
|
// DisableQuitOnLastWindowClosed disables the auto quit of the application if the last window has been closed.
|
|
DisableQuitOnLastWindowClosed bool
|
|
|
|
// ProgramName is used to set the program's name for the window manager via GTK's g_set_prgname().
|
|
//This name should not be localized. [see the docs]
|
|
//
|
|
//When a .desktop file is created this value helps with window grouping and desktop icons when the .desktop file's Name
|
|
//property differs form the executable's filename.
|
|
//
|
|
//[see the docs]: https://docs.gtk.org/glib/func.set_prgname.html
|
|
ProgramName string
|
|
}
|