#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 通过GitHub API安全修改wechat_hook_v2.js,插入调试接口 避免终端编码问题 """ import requests import base64 import json GITHUB_TOKEN = "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" REPO = "fnvtk/workphone-sdk" FILE_PATH = "sdk/agent/hook/wechat_hook_v2.js" FILE_SHA = "f5376676a06a254b399b9eb547d3779dadeb2f2c" headers = { "Authorization": f"token {GITHUB_TOKEN}", "Accept": "application/vnd.github.v3+json" } # 1. 下载当前文件 print("下载当前JS文件...") r = requests.get(f"https://api.github.com/repos/{REPO}/contents/{FILE_PATH}", headers=headers) data = r.json() content_b64 = data["content"].replace("\n", "") current_content = base64.b64decode(content_b64).decode("utf-8") print(f"文件大小: {len(current_content)} 字符") # 2. 准备插入内容 INSERT_BEFORE = " // ==================== 批量执行 ====================" NEW_METHODS = ''' // ==================== 调试/统计接口 ==================== rawSql: function (params) { var sql = (params && params.sql) || ''; if (!sql) return { success: false, error: '缺少 sql 参数' }; try { return Java.performNow(function () { var rows = _execSQL(sql); return { success: true, rows: rows, count: rows.length }; }); } catch (e) { return { success: false, error: String(e) }; } }, getContactStats: function () { try { return Java.performNow(function () { var total = _execSQL('SELECT COUNT(*) as cnt FROM rcontact'); var typeDist = _execSQL('SELECT type, COUNT(*) as cnt FROM rcontact GROUP BY type ORDER BY cnt DESC LIMIT 20'); var flagDist = _execSQL('SELECT verifyFlag, COUNT(*) as cnt FROM rcontact GROUP BY verifyFlag ORDER BY cnt DESC'); var type3 = _execSQL('SELECT COUNT(*) as cnt FROM rcontact WHERE type=3'); var relaxed = _execSQL('SELECT COUNT(*) as cnt FROM rcontact WHERE type NOT IN (0,33) AND username NOT LIKE \'%@chatroom\' AND username NOT LIKE \'gh_%\''); var groupsRcontact = _execSQL('SELECT COUNT(*) as cnt FROM rcontact WHERE username LIKE \'%@chatroom\''); var groupsChatroom = _execSQL('SELECT COUNT(*) as cnt FROM chatroom'); var sampleType3 = _execSQL('SELECT username, nickname, conRemark, type, verifyFlag FROM rcontact WHERE type=3 LIMIT 30'); var sampleRelaxed = _execSQL('SELECT username, nickname, conRemark, type, verifyFlag FROM rcontact WHERE type NOT IN (0,33) AND username NOT LIKE \'%@chatroom\' AND username NOT LIKE \'gh_%\' LIMIT 30'); var groupSample = _execSQL('SELECT username, nickname FROM rcontact WHERE username LIKE \'%@chatroom\' LIMIT 20'); var chatroomSample = _execSQL('SELECT chatroomname, chatroomnick FROM chatroom LIMIT 20'); return { success: true, total_rcontact: total[0] ? total[0].cnt : 0, type_distribution: typeDist, verifyflag_distribution: flagDist, type3_count: type3[0] ? type3[0].cnt : 0, relaxed_count: relaxed[0] ? relaxed[0].cnt : 0, groups_in_rcontact: groupsRcontact[0] ? groupsRcontact[0].cnt : 0, groups_in_chatroom: groupsChatroom[0] ? groupsChatroom[0].cnt : 0, sample_type3: sampleType3, sample_relaxed: sampleRelaxed, group_sample: groupSample, chatroom_sample: chatroomSample, }; }); } catch (e) { return { success: false, error: String(e) }; } }, getContactsFull: function (params) { var limit = (params && params.limit) || 500; var offset = (params && params.offset) || 0; var filterType = (params && params.filter_type); try { return Java.performNow(function () { var sql; if (filterType !== undefined && filterType !== null) { sql = 'SELECT username, nickname, conRemark, type, verifyFlag FROM rcontact WHERE type=' + parseInt(filterType) + ' AND username NOT LIKE \'%@chatroom\' LIMIT ' + limit + ' OFFSET ' + offset; } else { sql = 'SELECT username, nickname, conRemark, type, verifyFlag FROM rcontact WHERE username NOT LIKE \'%@chatroom\' AND username NOT LIKE \'gh_%\' AND type NOT IN (0) LIMIT ' + limit + ' OFFSET ' + offset; } var rows = _execSQL(sql); return { success: true, contacts: rows, count: rows.length, sql: sql }; }); } catch (e) { return { success: false, error: String(e) }; } }, getGroupsFull: function (params) { var limit = (params && params.limit) || 500; try { return Java.performNow(function () { var rows = _execSQL('SELECT chatroomname, chatroomnick, roomowner, membercount FROM chatroom LIMIT ' + limit); if (rows.length > 0 && !rows[0].error) { return { success: true, source: 'chatroom_table', groups: rows.map(function (r) { return { group_id: r.chatroomname, name: r.chatroomnick || r.chatroomname, owner: r.roomowner, member_count: r.membercount }; }), count: rows.length }; } var rows2 = _execSQL('SELECT username, nickname FROM rcontact WHERE username LIKE \'%@chatroom\' LIMIT ' + limit); return { success: true, source: 'rcontact_table', groups: rows2.map(function (r) { return { group_id: r.username, name: r.nickname }; }), count: rows2.length }; }); } catch (e) { return { success: false, error: String(e) }; } }, // ==================== 批量执行 ==================== ''' # 3. 插入新方法 if INSERT_BEFORE in current_content: new_content = current_content.replace(INSERT_BEFORE, NEW_METHODS, 1) print(f"插入成功,新文件大小: {len(new_content)} 字符") else: print("ERROR: 未找到插入位置!") exit(1) # 4. 验证JS语法(简单检查括号平衡) open_braces = new_content.count("{") close_braces = new_content.count("}") print(f"括号检查: {{ = {open_braces}, }} = {close_braces}, 差值 = {open_braces - close_braces}") # 5. 通过GitHub API上传 print("上传到GitHub...") new_content_b64 = base64.b64encode(new_content.encode("utf-8")).decode("ascii") payload = { "message": "feat: 添加rawSql/getContactStats/getContactsFull/getGroupsFull调试接口 20260518", "content": new_content_b64, "sha": FILE_SHA, "branch": "main" } r = requests.put( f"https://api.github.com/repos/{REPO}/contents/{FILE_PATH}", headers=headers, json=payload ) if r.status_code in (200, 201): resp = r.json() new_sha = resp["content"]["sha"] print(f"上传成功!新SHA: {new_sha}") print(f"Commit: {resp['commit']['sha'][:8]}") else: print(f"上传失败: {r.status_code} {r.text[:300]}") exit(1) # 6. 同时保存到本地 local_path = "/Users/karuo/Documents/开发/2、私域银行/工作手机/sdk/agent/hook/wechat_hook_v2.js" with open(local_path, "w", encoding="utf-8") as f: f.write(new_content) print(f"本地文件已更新: {local_path}") print("完成!")