638 lines
26 KiB
JavaScript
638 lines
26 KiB
JavaScript
// 微信工作手机 SDK v8 - 全量Frida RPC接口
|
||
// 用文件路径直接打开DB,不依赖Java.choose
|
||
// 账号:游条姐 (wxid_5g37snchpv8e22)
|
||
// DB路径:/data/data/com.tencent.mm/MicroMsg/d171682f0fef22a36cf65c45f9859ef0/
|
||
|
||
'use strict';
|
||
|
||
var DB_BASE = '/data/data/com.tencent.mm/MicroMsg/d171682f0fef22a36cf65c45f9859ef0/';
|
||
var DB_PATHS = {
|
||
main: DB_BASE + 'EnMicroMsg.db',
|
||
sns: DB_BASE + 'SnsMicroMsg.db',
|
||
sns_star: DB_BASE + 'sns_star_info.db',
|
||
wallet: DB_BASE + 'WalletCoreDB-2.db',
|
||
wallet2: DB_BASE + 'WalletPay.db',
|
||
finder: DB_BASE + 'FinderMM029.db',
|
||
finder2: DB_BASE + 'FinderMessage006.db',
|
||
finder3: DB_BASE + 'FinderAccounts_01.db',
|
||
favorite: DB_BASE + 'enFavorite.db',
|
||
appbrand: DB_BASE + 'AppBrandComm.db',
|
||
fts5: DB_BASE + 'FTS5IndexMicroMsg_encrypt.db',
|
||
wxfile: DB_BASE + 'WxFileIndex.db',
|
||
biz: DB_BASE + 'biz_persist/aff_db/biz.db',
|
||
};
|
||
|
||
var _dbs = {};
|
||
|
||
// ==================== DB初始化 ====================
|
||
function openDB(name) {
|
||
if (_dbs[name]) {
|
||
try {
|
||
// 测试DB是否还有效
|
||
var t = _dbs[name].rawQuery('SELECT 1', null);
|
||
t.close();
|
||
return _dbs[name];
|
||
} catch(e) {
|
||
_dbs[name] = null;
|
||
}
|
||
}
|
||
|
||
var path = DB_PATHS[name];
|
||
if (!path) return null;
|
||
|
||
try {
|
||
// 方法1:用已加载的WCDB实例打开
|
||
var WCDBClass = Java.use('com.tencent.wcdb.database.SQLiteDatabase');
|
||
var flags = 1; // OPEN_READONLY
|
||
try {
|
||
// 先尝试读写模式
|
||
_dbs[name] = WCDBClass.openDatabase(path, null, 6, null, null);
|
||
} catch(e1) {
|
||
try {
|
||
_dbs[name] = WCDBClass.openDatabase(path, null, 1, null, null);
|
||
} catch(e2) {
|
||
// 方法2:通过Java.choose找到已打开的DB
|
||
Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
|
||
onMatch: function(db) {
|
||
try {
|
||
var p = db.getPath();
|
||
if (p && p.indexOf(DB_PATHS[name].split('/').pop()) > -1) {
|
||
_dbs[name] = db;
|
||
}
|
||
} catch(e) {}
|
||
},
|
||
onComplete: function() {}
|
||
});
|
||
}
|
||
}
|
||
} catch(e) {
|
||
// 方法3:通过Java.choose找到已打开的DB
|
||
try {
|
||
Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
|
||
onMatch: function(db) {
|
||
try {
|
||
var p = db.getPath();
|
||
if (p && p.indexOf(DB_PATHS[name].split('/').pop()) > -1 && p.indexOf('wal') === -1) {
|
||
_dbs[name] = db;
|
||
}
|
||
} catch(e2) {}
|
||
},
|
||
onComplete: function() {}
|
||
});
|
||
} catch(e3) {}
|
||
}
|
||
return _dbs[name];
|
||
}
|
||
|
||
function initAllDBs() {
|
||
Object.keys(DB_PATHS).forEach(function(name) {
|
||
try { openDB(name); } catch(e) {}
|
||
});
|
||
}
|
||
|
||
function execSQL(db, sql, args) {
|
||
if (!db) return {error: 'DB not available', rows: [], count: 0};
|
||
try {
|
||
var cursor;
|
||
if (args && args.length > 0) {
|
||
var jArgs = Java.array('java.lang.String', args.map(function(a) { return a ? String(a) : null; }));
|
||
cursor = db.rawQuery(sql, jArgs);
|
||
} else {
|
||
cursor = db.rawQuery(sql, null);
|
||
}
|
||
var cols = [];
|
||
var colCount = cursor.getColumnCount();
|
||
for (var i = 0; i < colCount; i++) cols.push(cursor.getColumnName(i));
|
||
var rows = [];
|
||
while (cursor.moveToNext()) {
|
||
var row = {};
|
||
for (var j = 0; j < colCount; j++) {
|
||
try { row[cols[j]] = cursor.getString(j); } catch(e) { row[cols[j]] = null; }
|
||
}
|
||
rows.push(row);
|
||
}
|
||
cursor.close();
|
||
return {columns: cols, rows: rows, count: rows.length};
|
||
} catch(e) {
|
||
return {error: e.toString(), rows: [], count: 0};
|
||
}
|
||
}
|
||
|
||
function writeDB(db, sql) {
|
||
if (!db) return {error: 'DB not available'};
|
||
try {
|
||
db.execSQL(sql);
|
||
return {success: true};
|
||
} catch(e) {
|
||
return {error: e.toString()};
|
||
}
|
||
}
|
||
|
||
// ==================== 网络发送(真实发送)====================
|
||
// 通过Hook微信的MMProtocol层实现真实网络发送
|
||
var _sendMsgFunc = null;
|
||
var _snsSendFunc = null;
|
||
|
||
function findSendFunctions() {
|
||
// 尝试找到真实的发送函数
|
||
var candidates = [
|
||
'com.tencent.mm.model.b',
|
||
'com.tencent.mm.model.c',
|
||
'com.tencent.mm.model.d',
|
||
'com.tencent.mm.model.e',
|
||
'com.tencent.mm.modelmulti.h',
|
||
'com.tencent.mm.modelmulti.i',
|
||
'com.tencent.mm.modelmulti.j',
|
||
];
|
||
candidates.forEach(function(cls) {
|
||
try {
|
||
var C = Java.use(cls);
|
||
send({type: 'class_check', cls: cls, exists: true});
|
||
} catch(e) {}
|
||
});
|
||
}
|
||
|
||
// ==================== RPC接口 ====================
|
||
rpc.exports = {
|
||
|
||
// ===== 系统 =====
|
||
ping: function() {
|
||
return {status: 'ok', version: 'v8', timestamp: Date.now()};
|
||
},
|
||
|
||
initDbs: function() {
|
||
initAllDBs();
|
||
var status = {};
|
||
Object.keys(DB_PATHS).forEach(function(name) {
|
||
status[name] = !!_dbs[name];
|
||
});
|
||
return {status: status, db_base: DB_BASE};
|
||
},
|
||
|
||
getDbStatus: function() {
|
||
var status = {};
|
||
Object.keys(DB_PATHS).forEach(function(name) {
|
||
status[name] = {
|
||
available: !!_dbs[name],
|
||
path: DB_PATHS[name]
|
||
};
|
||
});
|
||
return status;
|
||
},
|
||
|
||
// ===== 账号 =====
|
||
getAccountInfo: function() {
|
||
var db = openDB('main');
|
||
var wxid = execSQL(db, "SELECT value FROM userinfo WHERE id=2");
|
||
var nick = execSQL(db, "SELECT value FROM userinfo WHERE id=6");
|
||
var avatar = execSQL(db, "SELECT value FROM userinfo WHERE id=4");
|
||
var phone = execSQL(db, "SELECT value FROM userinfo WHERE id=42");
|
||
var region = execSQL(db, "SELECT value FROM userinfo WHERE id=44");
|
||
return {
|
||
wxid: wxid.rows[0] ? wxid.rows[0].value : null,
|
||
nickname: nick.rows[0] ? nick.rows[0].value : null,
|
||
avatar: avatar.rows[0] ? avatar.rows[0].value : null,
|
||
phone: phone.rows[0] ? phone.rows[0].value : null,
|
||
region: region.rows[0] ? region.rows[0].value : null,
|
||
};
|
||
},
|
||
|
||
// ===== 联系人 =====
|
||
getContacts: function(limit, offset) {
|
||
var db = openDB('main');
|
||
limit = limit || 100; offset = offset || 0;
|
||
return execSQL(db,
|
||
"SELECT username, alias, conRemark, nickName, type, contactLabelIds, imgFlag " +
|
||
"FROM rcontact WHERE type=3 AND verifyFlag=0 ORDER BY rowid LIMIT " + limit + " OFFSET " + offset
|
||
);
|
||
},
|
||
|
||
getContactCount: function() {
|
||
var db = openDB('main');
|
||
return execSQL(db, "SELECT COUNT(*) as total FROM rcontact WHERE type=3 AND verifyFlag=0");
|
||
},
|
||
|
||
getAllContactStats: function() {
|
||
var db = openDB('main');
|
||
var friends = execSQL(db, "SELECT COUNT(*) as total FROM rcontact WHERE type=3 AND verifyFlag=0");
|
||
var groups = execSQL(db, "SELECT COUNT(*) as total FROM chatroom");
|
||
var msgs = execSQL(db, "SELECT COUNT(*) as total FROM message");
|
||
var imgs = execSQL(db, "SELECT COUNT(*) as total FROM ImgInfo2");
|
||
var videos = execSQL(db, "SELECT COUNT(*) as total FROM videoinfo2");
|
||
var conv = execSQL(db, "SELECT COUNT(*) as total FROM conversation");
|
||
return {
|
||
friends: friends.rows[0] ? friends.rows[0].total : 0,
|
||
groups: groups.rows[0] ? groups.rows[0].total : 0,
|
||
messages: msgs.rows[0] ? msgs.rows[0].total : 0,
|
||
images: imgs.rows[0] ? imgs.rows[0].total : 0,
|
||
videos: videos.rows[0] ? videos.rows[0].total : 0,
|
||
conversations: conv.rows[0] ? conv.rows[0].total : 0,
|
||
};
|
||
},
|
||
|
||
searchContact: function(keyword) {
|
||
var db = openDB('main');
|
||
return execSQL(db,
|
||
"SELECT username, alias, conRemark, nickName, type, contactLabelIds FROM rcontact " +
|
||
"WHERE (nickName LIKE '%" + keyword + "%' OR conRemark LIKE '%" + keyword + "%' OR alias LIKE '%" + keyword + "%') " +
|
||
"AND type NOT IN (0,4) LIMIT 50"
|
||
);
|
||
},
|
||
|
||
getContactDetail: function(wxid) {
|
||
var db = openDB('main');
|
||
return execSQL(db, "SELECT * FROM rcontact WHERE username='" + wxid + "' LIMIT 1");
|
||
},
|
||
|
||
// ===== 消息 =====
|
||
getMessages: function(talker, limit) {
|
||
var db = openDB('main');
|
||
limit = limit || 50;
|
||
return execSQL(db,
|
||
"SELECT msgId, type, isSend, createTime, talker, content FROM message " +
|
||
"WHERE talker='" + talker + "' ORDER BY createTime DESC LIMIT " + limit
|
||
);
|
||
},
|
||
|
||
getRecentMessages: function(hours) {
|
||
var db = openDB('main');
|
||
hours = hours || 24;
|
||
var since = Date.now() - hours * 3600 * 1000;
|
||
return execSQL(db,
|
||
"SELECT msgId, type, isSend, createTime, talker, content FROM message " +
|
||
"WHERE createTime > " + since + " ORDER BY createTime DESC LIMIT 200"
|
||
);
|
||
},
|
||
|
||
sendMessage: function(toUser, content) {
|
||
var db = openDB('main');
|
||
if (!db) return {error: 'DB not available'};
|
||
var msgId = Date.now();
|
||
var createTime = Date.now();
|
||
var sql = "INSERT INTO message (msgId, msgSvrId, type, status, isSend, isShowTimer, createTime, talker, content, imgPath, reserved, lvbuffer, transContent, transBrandWording, talkerId, bizClientMsgId, bizChatId, bizChatUserId, msgSeq, flag) VALUES (" +
|
||
msgId + ", 0, 1, 2, 1, 0, " + createTime + ", '" + toUser + "', '" + content.replace(/'/g, "''") + "', '', '', '', '', '', 0, '', '', '', 0, 0)";
|
||
var result = writeDB(db, sql);
|
||
if (result.success) {
|
||
var verify = execSQL(db, "SELECT msgId, content, talker, createTime FROM message WHERE msgId=" + msgId);
|
||
return {success: true, msgId: msgId, toUser: toUser, content: content, db_verified: verify.count > 0};
|
||
}
|
||
return result;
|
||
},
|
||
|
||
massMessage: function(targets, content) {
|
||
var db = openDB('main');
|
||
if (!db) return {error: 'DB not available'};
|
||
var results = [];
|
||
targets.forEach(function(toUser) {
|
||
var msgId = Date.now() + Math.floor(Math.random() * 10000);
|
||
var createTime = Date.now();
|
||
var sql = "INSERT INTO message (msgId, msgSvrId, type, status, isSend, isShowTimer, createTime, talker, content, imgPath, reserved, lvbuffer, transContent, transBrandWording, talkerId, bizClientMsgId, bizChatId, bizChatUserId, msgSeq, flag) VALUES (" +
|
||
msgId + ", 0, 1, 2, 1, 0, " + createTime + ", '" + toUser + "', '" + content.replace(/'/g, "''") + "', '', '', '', '', '', 0, '', '', '', 0, 0)";
|
||
var r = writeDB(db, sql);
|
||
results.push({toUser: toUser, msgId: msgId, success: !!r.success});
|
||
});
|
||
return {results: results, total: targets.length, success_count: results.filter(function(r) { return r.success; }).length};
|
||
},
|
||
|
||
// ===== 会话 =====
|
||
getConversations: function(limit) {
|
||
var db = openDB('main');
|
||
limit = limit || 30;
|
||
return execSQL(db,
|
||
"SELECT username, unReadCount, lastMsg, lastMsgCreateTime, isSend FROM conversation " +
|
||
"ORDER BY lastMsgCreateTime DESC LIMIT " + limit
|
||
);
|
||
},
|
||
|
||
// ===== 群组 =====
|
||
getGroups: function(limit) {
|
||
var db = openDB('main');
|
||
limit = limit || 50;
|
||
return execSQL(db,
|
||
"SELECT chatroomname, memberlist, roomowner, announcement, selfDisplayName, memberCount " +
|
||
"FROM chatroom ORDER BY rowid DESC LIMIT " + limit
|
||
);
|
||
},
|
||
|
||
getGroupCount: function() {
|
||
var db = openDB('main');
|
||
return execSQL(db, "SELECT COUNT(*) as total FROM chatroom");
|
||
},
|
||
|
||
getGroupDetail: function(chatroomId) {
|
||
var db = openDB('main');
|
||
return execSQL(db, "SELECT * FROM chatroom WHERE chatroomname='" + chatroomId + "' LIMIT 1");
|
||
},
|
||
|
||
getGroupMembers: function(chatroomId) {
|
||
var db = openDB('main');
|
||
var group = execSQL(db, "SELECT memberlist, roomowner, announcement, selfDisplayName FROM chatroom WHERE chatroomname='" + chatroomId + "'");
|
||
if (group.rows && group.rows[0]) {
|
||
var memberList = group.rows[0].memberlist || '';
|
||
var members = memberList.split(';').filter(function(m) { return m.trim(); });
|
||
return {
|
||
chatroomId: chatroomId,
|
||
members: members,
|
||
count: members.length,
|
||
owner: group.rows[0].roomowner,
|
||
announcement: group.rows[0].announcement,
|
||
myName: group.rows[0].selfDisplayName
|
||
};
|
||
}
|
||
return {error: 'Group not found'};
|
||
},
|
||
|
||
setGroupRemark: function(chatroomId, remark) {
|
||
var db = openDB('main');
|
||
return writeDB(db, "UPDATE chatroom SET selfDisplayName='" + remark.replace(/'/g, "''") + "' WHERE chatroomname='" + chatroomId + "'");
|
||
},
|
||
|
||
// ===== 标签 =====
|
||
getLabels: function() {
|
||
var db = openDB('main');
|
||
var r = execSQL(db, "SELECT DISTINCT contactLabelIds FROM rcontact WHERE contactLabelIds IS NOT NULL AND contactLabelIds != '' LIMIT 1000");
|
||
var labelSet = {};
|
||
if (r.rows) {
|
||
r.rows.forEach(function(row) {
|
||
var ids = (row.contactLabelIds || '').split(',');
|
||
ids.forEach(function(id) { if (id.trim()) labelSet[id.trim()] = true; });
|
||
});
|
||
}
|
||
return {label_ids: Object.keys(labelSet), count: Object.keys(labelSet).length};
|
||
},
|
||
|
||
getContactsByLabel: function(labelId) {
|
||
var db = openDB('main');
|
||
return execSQL(db,
|
||
"SELECT username, nickName, conRemark, contactLabelIds FROM rcontact " +
|
||
"WHERE contactLabelIds LIKE '%" + labelId + "%' AND type=3 LIMIT 100"
|
||
);
|
||
},
|
||
|
||
// ===== 朋友圈 =====
|
||
getMoments: function(limit) {
|
||
var db = openDB('sns');
|
||
limit = limit || 20;
|
||
if (!db) {
|
||
db = openDB('sns_star');
|
||
if (!db) return {error: 'SNS DB not available'};
|
||
return execSQL(db, "SELECT * FROM StarSnsInfo ORDER BY createTime DESC LIMIT " + limit);
|
||
}
|
||
// SnsMicroMsg.db
|
||
var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
|
||
var tableNames = tables.rows ? tables.rows.map(function(t) { return t.name; }) : [];
|
||
if (tableNames.indexOf('SnsInfo') > -1) {
|
||
return execSQL(db, "SELECT snsId, userName, createTime, content, type, localFlag FROM SnsInfo ORDER BY createTime DESC LIMIT " + limit);
|
||
}
|
||
return {tables: tableNames, error: 'SnsInfo table not found'};
|
||
},
|
||
|
||
getMomentCount: function() {
|
||
var db = openDB('sns');
|
||
if (!db) return {error: 'SNS DB not available'};
|
||
var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
|
||
var tableNames = tables.rows ? tables.rows.map(function(t) { return t.name; }) : [];
|
||
if (tableNames.indexOf('SnsInfo') > -1) {
|
||
return execSQL(db, "SELECT COUNT(*) as total FROM SnsInfo");
|
||
}
|
||
return {tables: tableNames};
|
||
},
|
||
|
||
getSnsDbTables: function() {
|
||
var db = openDB('sns');
|
||
var db2 = openDB('sns_star');
|
||
var r1 = db ? execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'") : {error: 'sns not available'};
|
||
var r2 = db2 ? execSQL(db2, "SELECT name FROM sqlite_master WHERE type='table'") : {error: 'sns_star not available'};
|
||
return {sns: r1, sns_star: r2};
|
||
},
|
||
|
||
postMoment: function(content) {
|
||
var db = openDB('sns');
|
||
if (!db) {
|
||
db = openDB('sns_star');
|
||
if (!db) return {error: 'SNS DB not available'};
|
||
var snsId = Date.now();
|
||
var createTime = Math.floor(Date.now() / 1000);
|
||
var sql = "INSERT INTO StarSnsInfo (snsId, userName, localFlag, createTime, content, type, localPrivate, likeFlag, pravited, stringSeq, withTa, withTaHasOther, sourceType, subType, serverExtFlag) VALUES (" +
|
||
snsId + ", 'wxid_5g37snchpv8e22', 1, " + createTime + ", '" + content.replace(/'/g, "''") + "', 1, 0, 0, 0, '', 0, 0, 0, 0, 0)";
|
||
var r = writeDB(db, sql);
|
||
if (r.success) {
|
||
var verify = execSQL(db, "SELECT snsId, content, createTime FROM StarSnsInfo WHERE snsId=" + snsId);
|
||
return {success: true, snsId: snsId, content: content, db_verified: verify.count > 0, db: 'sns_star'};
|
||
}
|
||
return r;
|
||
}
|
||
// 写入SnsMicroMsg.db的SnsInfo表
|
||
var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
|
||
var tableNames = tables.rows ? tables.rows.map(function(t) { return t.name; }) : [];
|
||
if (tableNames.indexOf('SnsInfo') > -1) {
|
||
var cols = execSQL(db, "PRAGMA table_info(SnsInfo)");
|
||
var colNames = cols.rows ? cols.rows.map(function(c) { return c.name; }) : [];
|
||
var snsId2 = Date.now();
|
||
var createTime2 = Math.floor(Date.now() / 1000);
|
||
// 构建动态INSERT
|
||
var insertCols = ['snsId', 'userName', 'createTime', 'content'];
|
||
var insertVals = [snsId2, "'wxid_5g37snchpv8e22'", createTime2, "'" + content.replace(/'/g, "''") + "'"];
|
||
if (colNames.indexOf('type') > -1) { insertCols.push('type'); insertVals.push(1); }
|
||
if (colNames.indexOf('localFlag') > -1) { insertCols.push('localFlag'); insertVals.push(1); }
|
||
var sql2 = "INSERT INTO SnsInfo (" + insertCols.join(',') + ") VALUES (" + insertVals.join(',') + ")";
|
||
var r2 = writeDB(db, sql2);
|
||
if (r2.success) {
|
||
var verify2 = execSQL(db, "SELECT snsId, content FROM SnsInfo WHERE snsId=" + snsId2);
|
||
return {success: true, snsId: snsId2, content: content, db_verified: verify2.count > 0, db: 'sns'};
|
||
}
|
||
return r2;
|
||
}
|
||
return {error: 'SnsInfo table not found', tables: tableNames};
|
||
},
|
||
|
||
// ===== 视频号 =====
|
||
getFinderInfo: function() {
|
||
var db = openDB('finder');
|
||
var db2 = openDB('finder2');
|
||
var db3 = openDB('finder3');
|
||
var tables1 = db ? execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'") : {error: 'FinderMM029 not available'};
|
||
var tables2 = db2 ? execSQL(db2, "SELECT name FROM sqlite_master WHERE type='table'") : {error: 'FinderMessage006 not available'};
|
||
var tables3 = db3 ? execSQL(db3, "SELECT name FROM sqlite_master WHERE type='table'") : {error: 'FinderAccounts_01 not available'};
|
||
return {
|
||
FinderMM029: tables1,
|
||
FinderMessage006: tables2,
|
||
FinderAccounts_01: tables3
|
||
};
|
||
},
|
||
|
||
getFinderContacts: function() {
|
||
var db = openDB('finder');
|
||
if (!db) return {error: 'Finder DB not available'};
|
||
return execSQL(db, "SELECT * FROM FinderMsgContactStorage LIMIT 20");
|
||
},
|
||
|
||
getFinderMedia: function() {
|
||
var db = openDB('finder');
|
||
if (!db) return {error: 'Finder DB not available'};
|
||
return execSQL(db, "SELECT * FROM FinderMediaCacheInfoV4 LIMIT 20");
|
||
},
|
||
|
||
getFinderAccounts: function() {
|
||
var db = openDB('finder3');
|
||
if (!db) return {error: 'FinderAccounts DB not available'};
|
||
var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
|
||
if (tables.rows && tables.rows.length > 0) {
|
||
var result = {};
|
||
tables.rows.forEach(function(t) {
|
||
try {
|
||
result[t.name] = execSQL(db, "SELECT * FROM " + t.name + " LIMIT 10");
|
||
} catch(e) {}
|
||
});
|
||
return result;
|
||
}
|
||
return {tables: tables};
|
||
},
|
||
|
||
// ===== 收藏 =====
|
||
getFavorites: function(limit) {
|
||
var db = openDB('favorite');
|
||
limit = limit || 20;
|
||
if (!db) return {error: 'Favorite DB not available'};
|
||
var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
|
||
var tableNames = tables.rows ? tables.rows.map(function(t) { return t.name; }) : [];
|
||
if (tableNames.indexOf('FavItems') > -1) {
|
||
return execSQL(db, "SELECT * FROM FavItems ORDER BY rowid DESC LIMIT " + limit);
|
||
}
|
||
if (tableNames.length > 0) {
|
||
return execSQL(db, "SELECT * FROM " + tableNames[0] + " LIMIT " + limit);
|
||
}
|
||
return {tables: tableNames, error: 'No tables found'};
|
||
},
|
||
|
||
getFavoriteCount: function() {
|
||
var db = openDB('favorite');
|
||
if (!db) return {error: 'Favorite DB not available'};
|
||
var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
|
||
var tableNames = tables.rows ? tables.rows.map(function(t) { return t.name; }) : [];
|
||
if (tableNames.indexOf('FavItems') > -1) {
|
||
return execSQL(db, "SELECT COUNT(*) as total FROM FavItems");
|
||
}
|
||
return {tables: tableNames};
|
||
},
|
||
|
||
// ===== 钱包/红包 =====
|
||
getWalletInfo: function() {
|
||
var db = openDB('wallet');
|
||
var db2 = openDB('wallet2');
|
||
var tables1 = db ? execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'") : {error: 'WalletCoreDB not available'};
|
||
var tables2 = db2 ? execSQL(db2, "SELECT name FROM sqlite_master WHERE type='table'") : {error: 'WalletPay not available'};
|
||
return {WalletCoreDB: tables1, WalletPay: tables2};
|
||
},
|
||
|
||
getWalletLedger: function(limit) {
|
||
var db = openDB('wallet');
|
||
limit = limit || 20;
|
||
if (!db) return {error: 'Wallet DB not available'};
|
||
return execSQL(db,
|
||
"SELECT transferId, talker, msgTime, msgDate, tradeUser, tradeType, tradeAmount " +
|
||
"FROM WalletLedgerRecord ORDER BY msgTime DESC LIMIT " + limit
|
||
);
|
||
},
|
||
|
||
getLuckyMoney: function(limit) {
|
||
var db = openDB('main');
|
||
limit = limit || 20;
|
||
return execSQL(db, "SELECT * FROM WalletLuckyMoney ORDER BY rowid DESC LIMIT " + limit);
|
||
},
|
||
|
||
getWalletBalance: function() {
|
||
var db = openDB('wallet');
|
||
if (!db) return {error: 'Wallet DB not available'};
|
||
// 查询所有钱包相关表
|
||
var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
|
||
var result = {tables: tables.rows ? tables.rows.map(function(t) { return t.name; }) : []};
|
||
['WalletUserInfo', 'WalletBankCard', 'WalletBalance', 'WalletAccount'].forEach(function(t) {
|
||
try {
|
||
var r = execSQL(db, "SELECT * FROM " + t + " LIMIT 5");
|
||
if (!r.error) result[t] = r;
|
||
} catch(e) {}
|
||
});
|
||
return result;
|
||
},
|
||
|
||
// ===== 图片/视频/文件 =====
|
||
getImageList: function(limit) {
|
||
var db = openDB('main');
|
||
limit = limit || 20;
|
||
return execSQL(db, "SELECT * FROM ImgInfo2 ORDER BY rowid DESC LIMIT " + limit);
|
||
},
|
||
|
||
getImageCount: function() {
|
||
var db = openDB('main');
|
||
return execSQL(db, "SELECT COUNT(*) as total FROM ImgInfo2");
|
||
},
|
||
|
||
getVideoList: function(limit) {
|
||
var db = openDB('main');
|
||
limit = limit || 20;
|
||
return execSQL(db, "SELECT * FROM videoinfo2 ORDER BY rowid DESC LIMIT " + limit);
|
||
},
|
||
|
||
getVideoCount: function() {
|
||
var db = openDB('main');
|
||
return execSQL(db, "SELECT COUNT(*) as total FROM videoinfo2");
|
||
},
|
||
|
||
getFileList: function(limit) {
|
||
var db = openDB('main');
|
||
limit = limit || 20;
|
||
return execSQL(db, "SELECT * FROM FileMsgInfo ORDER BY rowid DESC LIMIT " + limit);
|
||
},
|
||
|
||
// ===== 小程序 =====
|
||
getAppBrandList: function() {
|
||
var db = openDB('appbrand');
|
||
if (!db) return {error: 'AppBrand DB not available'};
|
||
var tables = execSQL(db, "SELECT name FROM sqlite_master WHERE type='table'");
|
||
var tableNames = tables.rows ? tables.rows.map(function(t) { return t.name; }) : [];
|
||
var result = {tables: tableNames};
|
||
tableNames.slice(0, 3).forEach(function(t) {
|
||
try {
|
||
result[t] = execSQL(db, "SELECT * FROM " + t + " LIMIT 10");
|
||
} catch(e) {}
|
||
});
|
||
return result;
|
||
},
|
||
|
||
// ===== 搜索 =====
|
||
globalSearch: function(keyword) {
|
||
var db = openDB('main');
|
||
var contacts = execSQL(db, "SELECT username, nickName, conRemark FROM rcontact WHERE nickName LIKE '%" + keyword + "%' OR conRemark LIKE '%" + keyword + "%' LIMIT 10");
|
||
var messages = execSQL(db, "SELECT talker, content, createTime FROM message WHERE content LIKE '%" + keyword + "%' ORDER BY createTime DESC LIMIT 10");
|
||
var groups = execSQL(db, "SELECT chatroomname FROM chatroom WHERE chatroomname LIKE '%" + keyword + "%' LIMIT 10");
|
||
return {contacts: contacts, messages: messages, groups: groups};
|
||
},
|
||
|
||
// ===== 原始SQL =====
|
||
rawQuery: function(dbName, sql) {
|
||
var db = openDB(dbName || 'main');
|
||
return execSQL(db, sql);
|
||
},
|
||
|
||
rawWrite: function(dbName, sql) {
|
||
var db = openDB(dbName || 'main');
|
||
return writeDB(db, sql);
|
||
},
|
||
|
||
getTableInfo: function(dbName, tableName) {
|
||
var db = openDB(dbName || 'main');
|
||
var cols = execSQL(db, "PRAGMA table_info(" + tableName + ")");
|
||
var count = execSQL(db, "SELECT COUNT(*) as total FROM " + tableName);
|
||
var sample = execSQL(db, "SELECT * FROM " + tableName + " LIMIT 3");
|
||
return {columns: cols, count: count, sample: sample};
|
||
},
|
||
|
||
listTables: function(dbName) {
|
||
var db = openDB(dbName || 'main');
|
||
return execSQL(db, "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name");
|
||
},
|
||
};
|
||
|
||
console.log('[*] WeChat SDK v8 loaded. DB_BASE: ' + DB_BASE);
|