package extension import ( "errors" "os" "path/filepath" "strings" "github.com/tidwall/gjson" "golang.org/x/text/language" "github.com/moond4rk/hackbrowserdata/item" "github.com/moond4rk/hackbrowserdata/utils/fileutil" ) type ChromiumExtension []*extension type extension struct { ID string URL string Enabled bool Name string Description string Version string HomepageURL string } func (c *ChromiumExtension) Parse(_ []byte) error { profilePath, err := fileutil.ReadFile(item.TempChromiumExtension) if err != nil { return err } _ = os.Remove(item.TempChromiumExtension) var extensions *gjson.Result if result, err := readChromiumExts(filepath.Join(profilePath, "Secure Preferences")); err == nil { extensions = result } else if result, err := readChromiumExts(filepath.Join(profilePath, "Preferences")); err == nil { extensions = result } else { return err } extensions.ForEach(func(id, ext gjson.Result) bool { location := ext.Get("location") if !location.Exists() { return true } switch location.Int() { case 5, 10: // https://source.chromium.org/chromium/chromium/src/+/main:extensions/common/mojom/manifest.mojom return true } // https://source.chromium.org/chromium/chromium/src/+/main:extensions/browser/disable_reason.h enabled := !ext.Get("disable_reasons").Exists() b := ext.Get("manifest") if !b.Exists() { *c = append(*c, &extension{ ID: id.String(), Enabled: enabled, Name: ext.Get("path").String(), }) return true } *c = append(*c, &extension{ ID: id.String(), URL: getChromiumExtURL(id.String(), b.Get("update_url").String()), Enabled: enabled, Name: b.Get("name").String(), Description: b.Get("description").String(), Version: b.Get("version").String(), HomepageURL: b.Get("homepage_url").String(), }) return true }) return nil } func readChromiumExts(filename string) (*gjson.Result, error) { prefs, err := fileutil.ReadFile(filename) if err != nil { return nil, err } extensions := gjson.Parse(prefs).Get("extensions.settings") if extensions.Exists() { return &extensions, nil } return nil, errors.New("extensions not found") } func getChromiumExtURL(id, updateURL string) string { if strings.HasSuffix(updateURL, "clients2.google.com/service/update2/crx") { return "https://chrome.google.com/webstore/detail/" + id } else if strings.HasSuffix(updateURL, "edge.microsoft.com/extensionwebstorebase/v1/crx") { return "https://microsoftedge.microsoft.com/addons/detail/" + id } return "" } func (c *ChromiumExtension) Name() string { return "extension" } func (c *ChromiumExtension) Len() int { return len(*c) } type FirefoxExtension []*extension var lang = language.Und func (f *FirefoxExtension) Parse(_ []byte) error { s, err := fileutil.ReadFile(item.TempFirefoxExtension) if err != nil { return err } _ = os.Remove(item.TempFirefoxExtension) j := gjson.Parse(s) for _, v := range j.Get("addons").Array() { // https://searchfox.org/mozilla-central/source/toolkit/mozapps/extensions/internal/XPIDatabase.jsm#157 if v.Get("location").String() != "app-profile" { continue } if lang != language.Und { locale := findFirefoxLocale(v.Get("locales").Array(), lang) *f = append(*f, &extension{ ID: v.Get("id").String(), Enabled: v.Get("active").Bool(), Name: locale.Get("name").String(), Description: locale.Get("description").String(), Version: v.Get("version").String(), HomepageURL: locale.Get("homepageURL").String(), }) continue } *f = append(*f, &extension{ ID: v.Get("id").String(), Enabled: v.Get("active").Bool(), Name: v.Get("defaultLocale.name").String(), Description: v.Get("defaultLocale.description").String(), Version: v.Get("version").String(), HomepageURL: v.Get("defaultLocale.homepageURL").String(), }) } return nil } func findFirefoxLocale(locales []gjson.Result, targetLang language.Tag) gjson.Result { tags := make([]language.Tag, 0, len(locales)) indices := make([]int, 0, len(locales)) for i, locale := range locales { for _, tagStr := range locale.Get("locales").Array() { tag, _ := language.Parse(tagStr.String()) if tag == language.Und { continue } tags = append(tags, tag) indices = append(indices, i) } } _, tagIndex, _ := language.NewMatcher(tags).Match(targetLang) return locales[indices[tagIndex]] } func (f *FirefoxExtension) Name() string { return "extension" } func (f *FirefoxExtension) Len() int { return len(*f) }