package fst

import (
	"git.gensokyo.uk/security/fortify/dbus"
	"git.gensokyo.uk/security/fortify/helper/bwrap"
	"git.gensokyo.uk/security/fortify/internal/system"
)

const Tmp = "/.fortify"

// Config is used to seal an app
type Config struct {
	// application ID
	ID string `json:"id"`
	// value passed through to the child process as its argv
	Command []string `json:"command"`

	Confinement ConfinementConfig `json:"confinement"`
}

// ConfinementConfig defines fortified child's confinement
type ConfinementConfig struct {
	// numerical application id, determines uid in the init namespace
	AppID int `json:"app_id"`
	// list of supplementary groups to inherit
	Groups []string `json:"groups"`
	// passwd username in the sandbox, defaults to passwd name of target uid or chronos
	Username string `json:"username,omitempty"`
	// home directory in sandbox, empty for outer
	Inner string `json:"home_inner"`
	// home directory in init namespace
	Outer string `json:"home"`
	// bwrap sandbox confinement configuration
	Sandbox *SandboxConfig `json:"sandbox"`
	// extra acl entries to append
	ExtraPerms []*ExtraPermConfig `json:"extra_perms,omitempty"`

	// reference to a system D-Bus proxy configuration,
	// nil value disables system bus proxy
	SystemBus *dbus.Config `json:"system_bus,omitempty"`
	// reference to a session D-Bus proxy configuration,
	// nil value makes session bus proxy assume built-in defaults
	SessionBus *dbus.Config `json:"session_bus,omitempty"`

	// system resources to expose to the sandbox
	Enablements system.Enablements `json:"enablements"`
}

type ExtraPermConfig struct {
	Ensure  bool   `json:"ensure,omitempty"`
	Path    string `json:"path"`
	Read    bool   `json:"r,omitempty"`
	Write   bool   `json:"w,omitempty"`
	Execute bool   `json:"x,omitempty"`
}

func (e *ExtraPermConfig) String() string {
	buf := make([]byte, 0, 5+len(e.Path))
	buf = append(buf, '-', '-', '-')
	if e.Ensure {
		buf = append(buf, '+')
	}
	buf = append(buf, ':')
	buf = append(buf, []byte(e.Path)...)
	if e.Read {
		buf[0] = 'r'
	}
	if e.Write {
		buf[1] = 'w'
	}
	if e.Execute {
		buf[2] = 'x'
	}
	return string(buf)
}

type FilesystemConfig struct {
	// mount point in sandbox, same as src if empty
	Dst string `json:"dst,omitempty"`
	// host filesystem path to make available to sandbox
	Src string `json:"src"`
	// write access
	Write bool `json:"write,omitempty"`
	// device access
	Device bool `json:"dev,omitempty"`
	// fail if mount fails
	Must bool `json:"require,omitempty"`
}

// Template returns a fully populated instance of Config.
func Template() *Config {
	return &Config{
		ID: "org.chromium.Chromium",
		Command: []string{
			"chromium",
			"--ignore-gpu-blocklist",
			"--disable-smooth-scrolling",
			"--enable-features=UseOzonePlatform",
			"--ozone-platform=wayland",
		},
		Confinement: ConfinementConfig{
			AppID:    9,
			Groups:   []string{"video"},
			Username: "chronos",
			Outer:    "/var/lib/persist/home/org.chromium.Chromium",
			Inner:    "/var/lib/fortify",
			Sandbox: &SandboxConfig{
				Hostname:      "localhost",
				UserNS:        true,
				Net:           true,
				Dev:           true,
				Syscall:       &bwrap.SyscallPolicy{DenyDevel: true, Multiarch: true},
				NoNewSession:  true,
				MapRealUID:    true,
				DirectWayland: false,
				// example API credentials pulled from Google Chrome
				// DO NOT USE THESE IN A REAL BROWSER
				Env: map[string]string{
					"GOOGLE_API_KEY":               "AIzaSyBHDrl33hwRp4rMQY0ziRbj8K9LPA6vUCY",
					"GOOGLE_DEFAULT_CLIENT_ID":     "77185425430.apps.googleusercontent.com",
					"GOOGLE_DEFAULT_CLIENT_SECRET": "OTJgUOQcT7lO7GsGZq2G4IlT",
				},
				Filesystem: []*FilesystemConfig{
					{Src: "/nix/store"},
					{Src: "/run/current-system"},
					{Src: "/run/opengl-driver"},
					{Src: "/var/db/nix-channels"},
					{Src: "/var/lib/fortify/u0/org.chromium.Chromium",
						Dst: "/data/data/org.chromium.Chromium", Write: true, Must: true},
					{Src: "/dev/dri", Device: true},
				},
				Link:     [][2]string{{"/run/user/65534", "/run/user/150"}},
				Etc:      "/etc",
				AutoEtc:  true,
				Override: []string{"/var/run/nscd"},
			},
			ExtraPerms: []*ExtraPermConfig{
				{Path: "/var/lib/fortify/u0", Ensure: true, Execute: true},
				{Path: "/var/lib/fortify/u0/org.chromium.Chromium", Read: true, Write: true, Execute: true},
			},
			SystemBus: &dbus.Config{
				See:       nil,
				Talk:      []string{"org.bluez", "org.freedesktop.Avahi", "org.freedesktop.UPower"},
				Own:       nil,
				Call:      nil,
				Broadcast: nil,
				Log:       false,
				Filter:    true,
			},
			SessionBus: &dbus.Config{
				See: nil,
				Talk: []string{"org.freedesktop.Notifications", "org.freedesktop.FileManager1", "org.freedesktop.ScreenSaver",
					"org.freedesktop.secrets", "org.kde.kwalletd5", "org.kde.kwalletd6", "org.gnome.SessionManager"},
				Own: []string{"org.chromium.Chromium.*", "org.mpris.MediaPlayer2.org.chromium.Chromium.*",
					"org.mpris.MediaPlayer2.chromium.*"},
				Call:      map[string]string{"org.freedesktop.portal.*": "*"},
				Broadcast: map[string]string{"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"},
				Log:       false,
				Filter:    true,
			},
			Enablements: system.EWayland.Mask() | system.EDBus.Mask() | system.EPulse.Mask(),
		},
	}
}