mirror of
https://git.um-react.app/um/cli.git
synced 2025-11-28 03:33:02 +00:00
refactor: improve mmkv logic
This commit is contained in:
@@ -1,118 +1,75 @@
|
||||
package qmc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/samber/lo"
|
||||
mmkv "github.com/unlock-music/go-mmkv"
|
||||
go_mmkv "github.com/unlock-music/go-mmkv"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/exp/slices"
|
||||
"golang.org/x/text/unicode/norm"
|
||||
"unlock-music.dev/cli/algo/common"
|
||||
"unlock-music.dev/cli/internal/utils"
|
||||
)
|
||||
|
||||
var streamKeyVault mmkv.Vault
|
||||
|
||||
// TODO: move to factory
|
||||
func readKeyFromMMKV(file string, logger *zap.Logger) ([]byte, error) {
|
||||
if file == "" {
|
||||
return nil, errors.New("file path is required while reading key from mmkv")
|
||||
}
|
||||
|
||||
//goland:noinspection GoBoolExpressions
|
||||
if runtime.GOOS != "darwin" {
|
||||
return nil, errors.New("mmkv vault not supported on this platform")
|
||||
}
|
||||
|
||||
if streamKeyVault == nil {
|
||||
mmkvDir, err := getRelativeMMKVDir(file)
|
||||
if err != nil {
|
||||
mmkvDir, err = getDefaultMMKVDir()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("mmkv key valut not found: %w", err)
|
||||
}
|
||||
func mergeMMKVKeys(keys ...common.QMCKeys) common.QMCKeys {
|
||||
result := make(common.QMCKeys)
|
||||
for _, k := range keys {
|
||||
for key, value := range k {
|
||||
result[utils.NormalizeUnicode(key)] = utils.NormalizeUnicode(value)
|
||||
}
|
||||
|
||||
mgr, err := mmkv.NewManager(mmkvDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("init mmkv manager: %w", err)
|
||||
}
|
||||
|
||||
streamKeyVault, err = mgr.OpenVault("MMKVStreamEncryptId")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open mmkv vault: %w", err)
|
||||
}
|
||||
|
||||
logger.Debug("mmkv vault opened", zap.Strings("keys", streamKeyVault.Keys()))
|
||||
}
|
||||
|
||||
_, partName := filepath.Split(file)
|
||||
partName = normalizeUnicode(partName)
|
||||
|
||||
buf, err := streamKeyVault.GetBytes(file)
|
||||
if buf == nil {
|
||||
filePaths := streamKeyVault.Keys()
|
||||
fileNames := lo.Map(filePaths, func(filePath string, _ int) string {
|
||||
_, name := filepath.Split(filePath)
|
||||
return normalizeUnicode(name)
|
||||
})
|
||||
|
||||
for _, key := range fileNames { // fallback: match filename only
|
||||
if key != partName {
|
||||
continue
|
||||
}
|
||||
idx := slices.Index(fileNames, key)
|
||||
buf, err = streamKeyVault.GetBytes(filePaths[idx])
|
||||
if err != nil {
|
||||
logger.Warn("read key from mmkv", zap.String("key", filePaths[idx]), zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(buf) == 0 {
|
||||
return nil, errors.New("key not found in mmkv vault")
|
||||
}
|
||||
|
||||
return deriveKey(buf)
|
||||
return result
|
||||
}
|
||||
|
||||
func OpenMMKV(mmkvPath string, key string, logger *zap.Logger) error {
|
||||
filePath, fileName := filepath.Split(mmkvPath)
|
||||
mgr, err := mmkv.NewManager(filepath.Dir(filePath))
|
||||
func LoadMMKV(path string, key string, logger *zap.Logger) (result common.QMCKeys, err error) {
|
||||
mmkv_path := path
|
||||
mmkv_crc := path + ".crc"
|
||||
|
||||
mr, err := os.Open(mmkv_path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("init mmkv manager: %w", err)
|
||||
logger.Error("LoadMMKV: Could not open mmkv file", zap.Error(err))
|
||||
return nil, fmt.Errorf("LoadMMKV: open error: %w", err)
|
||||
}
|
||||
defer mr.Close()
|
||||
|
||||
cr, err := os.Open(mmkv_crc)
|
||||
if err == nil {
|
||||
// crc is optional
|
||||
cr = nil
|
||||
defer cr.Close()
|
||||
}
|
||||
|
||||
// If `vaultKey` is empty, the key is ignored.
|
||||
streamKeyVault, err = mgr.OpenVaultCrypto(fileName, key)
|
||||
|
||||
var password []byte = nil
|
||||
if key != "" {
|
||||
password = make([]byte, 16)
|
||||
copy(password, []byte(key))
|
||||
}
|
||||
mmkv, err := go_mmkv.NewMMKVReader(mr, password, cr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("open mmkv vault: %w", err)
|
||||
logger.Error("LoadMMKV: failed to create reader", zap.Error(err))
|
||||
return nil, fmt.Errorf("LoadMMKV: NewMMKVReader error: %w", err)
|
||||
}
|
||||
|
||||
logger.Debug("mmkv vault opened", zap.Strings("keys", streamKeyVault.Keys()))
|
||||
return nil
|
||||
result = make(common.QMCKeys)
|
||||
for !mmkv.IsEOF() {
|
||||
key, err := mmkv.ReadKey()
|
||||
if err != nil {
|
||||
logger.Error("LoadMMKV: read key error", zap.Error(err))
|
||||
return nil, fmt.Errorf("LoadMMKV: read key error: %w", err)
|
||||
}
|
||||
value, err := mmkv.ReadStringValue()
|
||||
if err != nil {
|
||||
logger.Error("LoadMMKV: read value error", zap.Error(err))
|
||||
return nil, fmt.Errorf("LoadMMKV: read value error: %w", err)
|
||||
}
|
||||
logger.Debug("LoadMMKV: read", zap.String("key", key), zap.String("value", value))
|
||||
result[utils.NormalizeUnicode(key)] = utils.NormalizeUnicode(value)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// /
|
||||
func readKeyFromMMKVCustom(mid string) ([]byte, error) {
|
||||
if streamKeyVault == nil {
|
||||
return nil, fmt.Errorf("mmkv vault not loaded")
|
||||
}
|
||||
|
||||
// get ekey from mmkv vault
|
||||
eKey, err := streamKeyVault.GetBytes(mid)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get eKey error: %w", err)
|
||||
}
|
||||
return deriveKey(eKey)
|
||||
}
|
||||
|
||||
// / getRelativeMMKVDir get mmkv dir relative to file (legacy QQMusic for macOS behaviour)
|
||||
// getRelativeMMKVDir get mmkv dir relative to file (legacy QQMusic for macOS behaviour)
|
||||
func getRelativeMMKVDir(file string) (string, error) {
|
||||
mmkvDir := filepath.Join(filepath.Dir(file), "../mmkv")
|
||||
if _, err := os.Stat(mmkvDir); err != nil {
|
||||
@@ -149,10 +106,3 @@ func getDefaultMMKVDir() (string, error) {
|
||||
|
||||
return mmkvDir, nil
|
||||
}
|
||||
|
||||
// normalizeUnicode normalizes unicode string to NFC.
|
||||
// since macOS may change some characters in the file name.
|
||||
// e.g. "ぜ"(e3 81 9c) -> "ぜ"(e3 81 9b e3 82 99)
|
||||
func normalizeUnicode(str string) string {
|
||||
return norm.NFC.String(str)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user