Files
workphone-sdk/sdk/agent/hook/wechat_api_v8.js

638 lines
26 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 微信工作手机 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);