wip cli + profile handling

This commit is contained in:
Chakib Ben Ziane 2019-02-20 18:39:45 +01:00
parent 5cbcf816a7
commit 9ed35b4149
9 changed files with 294 additions and 82 deletions

View File

@ -1,8 +1,11 @@
package main
import (
"gomark/mozilla"
"gomark/parsing"
"gomark/utils"
"os"
"path"
"git.sp4ke.com/sp4ke/gum"
"github.com/urfave/cli"
@ -15,6 +18,39 @@ var startServerCmd = cli.Command{
Action: startServer,
}
var unlockFirefoxCmd = cli.Command{
Name: "ff",
Usage: "Disable VFS lock in firefox",
Action: unlockFirefox,
}
func unlockFirefox(c *cli.Context) {
prefsPath := path.Join(mozilla.BookmarkDir, mozilla.PrefsFile)
pusers, err := utils.FileProcessUsers(path.Join(mozilla.BookmarkDir, mozilla.BookmarkFile))
if err != nil {
fflog.Error(err)
}
for pid, p := range pusers {
pname, err := p.Name()
if err != nil {
fflog.Error(err)
}
log.Errorf("multiprocess not enabled and %s(%d) is running. Close firefox and disable VFS lock", pname, pid)
}
// End testing
// enable multi process access in firefox
err = mozilla.SetPrefBool(prefsPath,
mozilla.PrefMultiProcessAccess,
true)
if err != nil {
log.Error(err)
}
}
func startServer(c *cli.Context) {
manager := gum.NewManager()
manager.ShutdownOn(os.Interrupt)

View File

@ -18,6 +18,7 @@ func main() {
app.Commands = []cli.Command{
startServerCmd,
unlockFirefoxCmd,
}
if err := app.Run(os.Args); err != nil {

View File

@ -1,11 +1,7 @@
package mozilla
import (
"errors"
"fmt"
"gomark/logging"
"gomark/utils"
"path"
)
var fflog = logging.GetLogger("FF")
@ -15,22 +11,6 @@ const (
BookmarkDir = "/home/spike/.mozilla/firefox/7otsk3vs.test_bookmarks"
)
const (
// This option disables the VFS lock on firefox
// Sqlite allows file locking of the database using the local file system VFS.
// Previous versions of FF allowed external processes to access the file.
//
// Since firefox v(63) this has changed. When initializing the database FF checks
// the preference option `storage.multiProcessAccess.enabled` which is not
// documented officially.
//
// Source code:
//- https://dxr.mozilla.org/mozilla-central/source/storage/TelemetryVFS.cpp#884
//- https://dxr.mozilla.org/mozilla-central/source/storage/mozStorageService.cpp#377
//- Change on github: https://github.com/mozilla/gecko-dev/commit/a543f35d4be483b19446304f52e4781d7a4a0a2f
PrefMultiProcessAccess = "storage.multiProcessAccess.enabled"
)
var (
// Default data source name query options for `places.sqlite` db
PlacesDSN = map[string]string{
@ -38,63 +18,3 @@ var (
}
log = logging.GetLogger("MOZ")
)
var (
ErrMultiProcessAlreadyEnabled = errors.New("multiProcessAccess already enabled")
)
//TODO: try unlock at the browser level !
// Try to unlock vfs locked places.sqlite by setting the `PrefMultiProcessAccess`
// property in prefs.js
func UnlockPlaces(dir string) error {
log.Debug("Unlocking places.sqlite ...")
prefsPath := path.Join(dir, PrefsFile)
// Find if multiProcessAccess option is defined
pref, err := GetPrefBool(prefsPath, PrefMultiProcessAccess)
if err != nil && err != ErrPrefNotFound {
return err
}
// If pref already defined and true raise an error
if pref {
log.Criticalf("pref <%s> already defined as <%v>",
PrefMultiProcessAccess, pref)
return ErrMultiProcessAlreadyEnabled
// Set the preference
} else {
// Checking if firefox is running
// TODO: #multiprocess add CLI to unlock places.sqlite
pusers, err := utils.FileProcessUsers(path.Join(BookmarkDir, BookmarkFile))
if err != nil {
fflog.Error(err)
}
for pid, p := range pusers {
pname, err := p.Name()
if err != nil {
fflog.Error(err)
}
return errors.New(fmt.Sprintf("multiprocess not enabled and %s(%d) is running", pname, pid))
}
// End testing
// enable multi process access in firefox
err = SetPrefBool(prefsPath,
PrefMultiProcessAccess,
true)
if err != nil {
return err
}
}
return nil
}

View File

@ -0,0 +1,92 @@
package mozilla
import (
"gomark/profiles"
"gomark/utils"
"path/filepath"
"regexp"
ini "gopkg.in/ini.v1"
)
const (
ProfilesFile = "profiles.ini"
)
var (
ConfigFolder = ".mozilla/firefox"
ReIniProfiles = regexp.MustCompile(`(?i)profile`)
)
type FFProfileManager struct {
basePath string
profilesFile *ini.File
}
func (pm *FFProfileManager) GetProfiles() ([]*profiles.Profile, error) {
sections := pm.profilesFile.Sections()
var filtered []*ini.Section
var result []*profiles.Profile
for _, section := range sections {
if ReIniProfiles.MatchString(section.Name()) {
filtered = append(filtered, section)
p := &profiles.Profile{
Id: section.Name(),
}
err := section.MapTo(p)
if err != nil {
return nil, err
}
result = append(result, p)
}
}
return result, nil
}
func (pm *FFProfileManager) ListProfiles() []string {
sections := pm.profilesFile.SectionStrings()
var result []string
for _, s := range sections {
if ReIniProfiles.MatchString(s) {
result = append(result, s)
}
}
return result
}
func NewFFProfileManager() (*FFProfileManager, error) {
profiles, err := ini.Load(filepath.Join(ConfigFolder, ProfilesFile))
if err != nil {
return nil, err
}
pm := &FFProfileManager{
basePath: ConfigFolder,
profilesFile: profiles,
}
return pm, nil
}
func init() {
ConfigFolder = filepath.Join(utils.GetHomeDir(), ConfigFolder)
// Check if base folder exists
configFolderExists, err := utils.CheckDirExists(ConfigFolder)
if !configFolderExists {
fflog.Criticalf("The base firefox folder <%s> does not exist",
ConfigFolder)
}
if err != nil {
fflog.Critical(err)
}
}

View File

@ -0,0 +1,43 @@
package mozilla
import (
"os"
"testing"
)
func TestNewProfileManager(t *testing.T) {
InitialConfigFolder := ConfigFolder
ConfigFolder = "toto"
_, err := NewFFProfileManager()
if !os.IsNotExist(err) {
t.Error(err)
}
ConfigFolder = InitialConfigFolder
}
func TestListProfiles(t *testing.T) {
pm, _ := NewFFProfileManager()
t.Log("Listing profiles")
profiles := pm.ListProfiles()
for _, p := range pm.ListProfiles() {
t.Logf("found profiles: %s", p)
}
if profiles[0] != "Profile0" {
t.Error("Expected at least Profile0")
}
}
func TestGetProfiles(t *testing.T) {
pm, _ := NewFFProfileManager()
profs, err := pm.GetProfiles()
if err != nil {
t.Error(err)
}
for _, p := range profs {
t.Log(p)
}
}

85
mozilla/firefox_vfs.go Normal file
View File

@ -0,0 +1,85 @@
package mozilla
import (
"errors"
"fmt"
"gomark/utils"
"path"
)
const (
// This option disables the VFS lock on firefox
// Sqlite allows file locking of the database using the local file system VFS.
// Previous versions of FF allowed external processes to access the file.
//
// Since firefox v(63) this has changed. When initializing the database FF checks
// the preference option `storage.multiProcessAccess.enabled` which is not
// documented officially.
//
// Source code:
//- https://dxr.mozilla.org/mozilla-central/source/storage/TelemetryVFS.cpp#884
//- https://dxr.mozilla.org/mozilla-central/source/storage/mozStorageService.cpp#377
//- Change on github: https://github.com/mozilla/gecko-dev/commit/a543f35d4be483b19446304f52e4781d7a4a0a2f
PrefMultiProcessAccess = "storage.multiProcessAccess.enabled"
)
var (
ErrMultiProcessAlreadyEnabled = errors.New("multiProcessAccess already enabled")
)
func UnlockPlaces(dir string) error {
log.Debug("Unlocking places.sqlite ...")
prefsPath := path.Join(dir, PrefsFile)
// Find if multiProcessAccess option is defined
pref, err := GetPrefBool(prefsPath, PrefMultiProcessAccess)
if err != nil && err != ErrPrefNotFound {
return err
}
// If pref already defined and true raise an error
if pref {
log.Criticalf("pref <%s> already defined as <%v>",
PrefMultiProcessAccess, pref)
return ErrMultiProcessAlreadyEnabled
// Set the preference
} else {
// Checking if firefox is running
// TODO: #multiprocess add CLI to unlock places.sqlite
pusers, err := utils.FileProcessUsers(path.Join(BookmarkDir, BookmarkFile))
if err != nil {
fflog.Error(err)
}
for pid, p := range pusers {
pname, err := p.Name()
if err != nil {
fflog.Error(err)
}
return errors.New(fmt.Sprintf("multiprocess not enabled and %s(%d) is running. Close firefox and disable VFS lock", pname, pid))
}
// End testing
// enable multi process access in firefox
err = SetPrefBool(prefsPath,
PrefMultiProcessAccess,
true)
if err != nil {
return err
}
}
return nil
}
//
//TODO: try unlock at the browser level !
// Try to unlock vfs locked places.sqlite by setting the `PrefMultiProcessAccess`
// property in prefs.js

20
profiles/profiles.go Normal file
View File

@ -0,0 +1,20 @@
// +build linux
//
package profiles
const (
XDG_HOME = "XDG_CONFIG_HOME"
)
type ProfileManager interface {
ListProfiles() []string
GetProfiles() []*Profile
GetDefaultProfile() Profile
}
type Profile struct {
Id string
Name string
Path string
}

View File

@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"os"
"os/user"
"path"
)
@ -11,6 +12,15 @@ func GetDefaultDBPath() string {
return "./"
}
func CheckDirExists(path string) (bool, error) {
info, err := os.Stat(path)
if err == nil {
return info.IsDir(), nil
}
return false, err
}
func CheckFileExists(file string) (bool, error) {
info, err := os.Stat(file)
if err == nil {
@ -56,3 +66,8 @@ func CheckWriteable(dir string) error {
return err
}
func GetHomeDir() string {
user, _ := user.Current()
return user.HomeDir
}

View File

@ -26,9 +26,9 @@ func FileProcessUsers(path string) (map[int32]*psutil.Process, error) {
for _, p := range processes {
files, err := p.OpenFiles()
_, isPathError := err.(*os.PathError)
if err != nil && isPathError {
//TODO: use os.IsNotExist to test the path error
if err != nil && os.IsNotExist(err) {
continue
}