Merge pull request #125 from moonD4rk/devpull/128/head
						commit
						2de62ac1bb
					
				| @ -0,0 +1,146 @@ | ||||
| package localstorage | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"database/sql" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/syndtr/goleveldb/leveldb" | ||||
| 
 | ||||
| 	"hack-browser-data/internal/item" | ||||
| 	"hack-browser-data/internal/log" | ||||
| 	"hack-browser-data/internal/utils/typeutil" | ||||
| ) | ||||
| 
 | ||||
| type ChromiumLocalStorage []storage | ||||
| 
 | ||||
| type storage struct { | ||||
| 	IsMeta bool | ||||
| 	URL    string | ||||
| 	Key    string | ||||
| 	Value  string | ||||
| } | ||||
| 
 | ||||
| func (c *ChromiumLocalStorage) Parse(masterKey []byte) error { | ||||
| 	db, err := leveldb.OpenFile(item.TempChromiumLocalStorage, nil) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer os.RemoveAll(item.TempChromiumLocalStorage) | ||||
| 	// log.Info("parsing local storage now")
 | ||||
| 	defer db.Close() | ||||
| 
 | ||||
| 	iter := db.NewIterator(nil, nil) | ||||
| 	for iter.Next() { | ||||
| 		key := iter.Key() | ||||
| 		value := iter.Value() | ||||
| 		// don't parse value upper than 5kB
 | ||||
| 		if len(value) > 1024*5 { | ||||
| 			continue | ||||
| 		} | ||||
| 		var s = new(storage) | ||||
| 		s.fillKey(key) | ||||
| 		s.fillValue(value) | ||||
| 		// don't save meta data
 | ||||
| 		if s.IsMeta { | ||||
| 			continue | ||||
| 		} | ||||
| 		*c = append(*c, *s) | ||||
| 	} | ||||
| 	iter.Release() | ||||
| 	err = iter.Error() | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func (c *ChromiumLocalStorage) Name() string { | ||||
| 	return "localStorage" | ||||
| } | ||||
| 
 | ||||
| func (s *storage) fillKey(b []byte) { | ||||
| 	keys := bytes.Split(b, []byte("\x00")) | ||||
| 	if len(keys) == 1 && bytes.HasPrefix(keys[0], []byte("META:")) { | ||||
| 		s.IsMeta = true | ||||
| 		s.fillMetaHeader(keys[0]) | ||||
| 	} | ||||
| 	if len(keys) == 2 && bytes.HasPrefix(keys[0], []byte("_")) { | ||||
| 		s.fillHeader(keys[0], keys[1]) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (s *storage) fillMetaHeader(b []byte) { | ||||
| 	s.URL = string(bytes.Trim(b, "META:")) | ||||
| } | ||||
| 
 | ||||
| func (s *storage) fillHeader(url, key []byte) { | ||||
| 	s.URL = string(bytes.Trim(url, "_")) | ||||
| 	s.Key = string(bytes.Trim(key, "\x01")) | ||||
| } | ||||
| 
 | ||||
| // fillValue fills value of the storage
 | ||||
| // TODO: support unicode charter
 | ||||
| func (s *storage) fillValue(b []byte) { | ||||
| 	t := fmt.Sprintf("%c", b) | ||||
| 	m := strings.NewReplacer(" ", "", "\x00", "", "\x01", "").Replace(t) | ||||
| 	s.Value = m | ||||
| } | ||||
| 
 | ||||
| type FirefoxLocalStorage []storage | ||||
| 
 | ||||
| const ( | ||||
| 	queryFirefoxHistory = `SELECT originKey, key, value FROM webappsstore2` | ||||
| 	closeJournalMode    = `PRAGMA journal_mode=off` | ||||
| ) | ||||
| 
 | ||||
| func (f *FirefoxLocalStorage) Parse(masterKey []byte) error { | ||||
| 	db, err := sql.Open("sqlite3", item.TempFirefoxLocalStorage) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer os.Remove(item.TempFirefoxLocalStorage) | ||||
| 	defer db.Close() | ||||
| 	_, err = db.Exec(closeJournalMode) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer db.Close() | ||||
| 	rows, err := db.Query(queryFirefoxHistory) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer rows.Close() | ||||
| 	for rows.Next() { | ||||
| 		var ( | ||||
| 			originKey, key, value string | ||||
| 		) | ||||
| 		if err = rows.Scan(&originKey, &key, &value); err != nil { | ||||
| 			log.Warn(err) | ||||
| 		} | ||||
| 		var s = new(storage) | ||||
| 		s.fillFirefox(originKey, key, value) | ||||
| 		*f = append(*f, *s) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (s *storage) fillFirefox(originKey, key, value string) { | ||||
| 	// originKey = moc.buhtig.:https:443
 | ||||
| 	p := strings.Split(originKey, ":") | ||||
| 	h := typeutil.Reverse([]byte(p[0])) | ||||
| 	if bytes.HasPrefix(h, []byte(".")) { | ||||
| 		h = h[1:] | ||||
| 	} | ||||
| 	if len(p) == 3 { | ||||
| 		s.URL = fmt.Sprintf("%s://%s:%s", p[1], string(h), p[2]) | ||||
| 	} | ||||
| 	s.Key = key | ||||
| 	s.Value = value | ||||
| } | ||||
| 
 | ||||
| func (f *FirefoxLocalStorage) Name() string { | ||||
| 	return "localStorage" | ||||
| } | ||||
| @ -0,0 +1,24 @@ | ||||
| package typeutil | ||||
| 
 | ||||
| import ( | ||||
| 	"testing" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	reverseTestCases = [][]any{ | ||||
| 		[]any{1, 2, 3, 4, 5}, | ||||
| 		[]any{"1", "2", "3", "4", "5"}, | ||||
| 		[]any{"1", 2, "3", "4", 5}, | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| func TestReverse(t *testing.T) { | ||||
| 	for _, ts := range reverseTestCases { | ||||
| 		h := Reverse(ts) | ||||
| 		for i := 0; i < len(ts); i++ { | ||||
| 			if h[len(h)-i-1] != ts[i] { | ||||
| 				t.Errorf("reverse failed %v != %v", h, ts) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
					Loading…
					
					
				
		Reference in new issue