45578~45599。
响应均为 application/json(下载类除外),已开启 Access-Control-Allow-Origin: *,并支持 OPTIONS 预检。
路径相对服务根,例如 http://<设备IP>:<端口>/api/overview。
POST 接口请用 Content-Type: application/json 提交(普通请求体上限 64KB,/api/upload 走流式上限 4GB);方法不匹配返回 405,未知路径返回 404。
一次性返回当前生效环境、偏好键值、全部环境名、导出/导入目录文件列表,以及三个目录的绝对路径。Web 控制台首页即用它。
{
"current": "原始机器",
"storedPreference": "原始机器",
"environments": ["原始机器", "20260610022719", "..."],
"exports": [{ "name": "原始机器.tar", "size": 30279680 }],
"imports": [{ "name": "aaa.tar", "size": 1024 }],
"paths": {
"data": "/var/mobile/Media/CVKShadowKit/data",
"export": "/var/mobile/Media/CVKShadowKit/export",
"import": "/var/mobile/Media/CVKShadowKit/import"
}
}
返回 current / storedPreference / environments。
{ "current": "原始机器", "storedPreference": "原始机器",
"environments": ["原始机器", "20260610022719", "..."] }
仅返回当前生效环境名。
{ "current": "原始机器" }
仅返回全部环境名数组。
{ "environments": ["原始机器", "20260610022719", "..."] }
判断指定环境是否存在。name(亦可 record/environment)必填;按目录实际名区分大小写匹配,未命中时再给出大小写不敏感的命中名以便纠正。
{ "name": "20260610022719", "exists": true, "caseInsensitiveMatch": null }
// 不存在但大小写不同:{ "name": "Env1", "exists": false, "caseInsensitiveMatch": "env1" }
仅返回环境名数组(旧版兼容)。
["原始机器", "20260610022719", "..."]
新建一个以时间戳命名的环境目录并选中,随后对其做一次快照。请求体可为空。
{ "created": "20260610213000", "current": "...", "environments": [...] }
切换生效环境:先备份当前环境 → 选中目标 → 终止相关进程并清理、再从记录恢复。默认切换后会自动刷新一次 IP 定位;如需跳过,加参数 skipIpRefresh。
{ "name": "环境目录名" } // 默认切换后刷新 IP
{ "name": "环境目录名", "skipIpRefresh": true } // 切换后不刷新 IP
// 也支持查询参数 ?name=环境目录名&skipIpRefresh=1
// 等价写法:refreshIp=false(同样跳过刷新)
{ "switchedTo": "...", "snapshotRecord": "...", "restoreTriggered": true,
"ipRefreshed": true, "current": "...", "environments": [...] }
重命名环境目录。不带 old 时默认重命名「当前激活环境」。不能重命名默认环境(原始机器)。若被改的是当前选中环境,会同步更新选中偏好。
{ "name": "新环境名" } // 重命名当前激活环境
{ "name": "新环境名", "old": "旧环境名" } // 重命名指定环境
// 也支持查询参数 ?name=新名&old=旧名
{ "renamedFrom": "20260610213000", "renamedTo": "新环境名",
"current": "新环境名", "environments": [...] }
| error | 状态码 | 说明 |
|---|---|---|
name_required | 400 | 未提供新名 |
default_immutable | 400 | 不能重命名「原始机器」 |
invalid_name | 400 | 新名非法(含非法字符等) |
same_name | 400 | 新旧名相同 |
name_exists | 400 | 目标名已存在(大小写不敏感) |
src_missing | 400 | 旧环境目录不存在 |
move_failed | 500 | 目录移动失败 |
一键新机:备份当前环境 → 新建时间戳空白环境并选中 → 清理真机数据(不恢复)。注入目标取持久化预设列表。请求体可为空。清理完成后默认会自动对新环境触发一次 IP 定位(与首页一键新机一致),把伪装 GPS 写入环境并刷新系统模拟定位(定位真正在系统中生效);请求同步阻塞至定位完成(最长约 35s),结果里带回 ipLocate。如需新机后不刷新 IP,加参数 skipIpRefresh(此时接口不阻塞、秒回,ipLocate 为 null)。
{ "skipIpRefresh": true } // 新机后不刷新 IP
// 也支持查询参数 ?skipIpRefresh=1
// 等价写法:refreshIp=false(同样跳过刷新)
{ "created": "20260610213000", "snapshotRecord": "...",
"ipRefreshed": true,
"ipLocate": { "ok": true, "located": true, "ip": "...",
"city": "...", "region": "...", "lat": 36.17, "lon": -115.07 },
"current": "...", "environments": [...] }
// skipIpRefresh 时: "ipRefreshed": false, "ipLocate": null
等价于首页「刷新 IP」按钮的完整动作(不是只读查询):对当前激活环境触发一次真实 IP 定位——查询出口 IP、把伪装 GPS 写入环境并刷新系统模拟定位(定位真正在系统中生效),首页同步显示「定位中…」。请求会同步阻塞至定位完成(含双接口轮换+交叉校验,最长约 35s),再返回刚定位到的结果。
{ "ok": true, "located": true, "ip": "1.2.3.4",
"city": "...", "region": "...", "region_code": "NV",
"country": "...", "country_code": "US",
"lat": 37.77, "lon": -122.41, "timezone": "...", "zip": "..." }
{ "ok": false, "error": "ip_locate_failed" } // 定位超时/全部接口失败
{ "ok": false, "error": "ip_locate_no_result" } // 定位成功但读回结果为空
设备出口 IP 信用分(与首页「IP 刷新成功后」调用的 Radar trackVerified 打分同一套)。默认会重新探测当前出口并阻塞等待结果(最长约 20s),分数 0–100,越高越干净。?cached=1 只读本地已缓存分、不打 Radar。别名:/api/radar/ipscore。
?cached=1 // 只读缓存,不探测;缺省或不传 = 重新探测
{ "ok": true, "score": 85, "cached": false, "source": "radar_trackVerified",
"ip": "1.2.3.4", "locatedIp": "1.2.3.4",
"lat": 37.77, "lon": -122.41,
"city": "...", "region": "...", "country_code": "US",
"passed": true,
"fraud": { "proxy": false, "mocked": false, "privacy": { "vpn": false, ... }, "asn": { ... } },
"privacy": { "vpn": false, "proxy": false, "tor": false, ... },
"asn": { "asn": "...", "type": "isp", ... },
"failureReasons": [], "warningReasons": [] }
{ "ok": false, "score": -1, "cached": false, "error": "probe_failed" }
{ "ok": false, "score": -1, "cached": false, "error": "timeout" }
{ "ok": false, "score": -1, "cached": true, "error": "no_cached_score" }
人设 / 网络一致性检查(独立方法 CVKNetworkConsistencyCheckRun)。对比:环境 sticky 出口国家、系统时区、伪装 GPS 与现场出口(默认只读探测,不写 GPS)、隧道网卡;并默认做 STUN 反射 IP≈WebRTC 与 系统 DNS 探测。别名:/api/net/consistency。
?probe=1 // 缺省:现场探测出口地理(只读) ?probe=0 // 只用本地 sticky / 上次定位 ?webrtc=1 // 缺省:UDP STUN → 反射公网 IP,与 HTTP 出口比对 ?dns=1 // 缺省:读系统 DNS,对照出口国家 ?radar=1 // 附带 Radar 出口分(阻塞) ?timeout=12 // 出口探测超时秒数
{ "ok": true, "level": "green", "summary": "一致性良好",
"checks": [
{ "id": "country", "title": "出口国家", "level": "green", "ok": true,
"detail": "出口国家与环境记录一致", "expected": "US", "observed": "US" },
{ "id": "webrtc", "title": "WebRTC(STUN)", "level": "green", "ok": true,
"detail": "STUN 反射 IP 与 HTTP 出口一致(…)" },
{ "id": "dns", "title": "DNS", "level": "green", "ok": true,
"detail": "存在私网 DNS + 隧道网卡,较像隧道内解析" }
],
"expected": { "environment": "...", "country_code": "US", "timezone": "...", ... },
"observed": { "ip": "...", "country_code": "US", "vpn_ifaces": ["utun4"],
"webrtc_srflx_ip": "...", "dns_servers": ["10.x.x.x"] },
"webrtc": { "status": "ok", "srflx_ip": "...", "match": "same", "server": "stun.l.google.com" },
"dns": { "status": "ok", "verdict": "private_with_tunnel", "servers": [ … ] } }
level=green 全项通过 level=yellow 有警告(IP 已变 / 无隧道网卡 / STUN 失败 / 公共 DNS 等) level=red 国家/时区不一致、STUN≠HTTP 出口、DNS 国家旁路,或出口探测失败
特例接口(仅 PayPal)。在当前激活环境里换取网页端免密登录地址,重建并发起 token_to_code 请求。
三级取参(按优先级自动回退):
① keychain:实时 token_storage/PFAuthTokenService 里 App 当前在用的 UserAccessToken(A23AA)+idToken(随会话刷新、长效,推荐)+ 最近一条 proxy-auth/token 抓包的设备指纹重建 body;
② proxy-auth/token 抓包:最近一条响应里的 UserAccessToken+idToken(仅 ~30 分钟)+ 同包指纹重建 body;
③ token_to_code 抓包:直接重放最近一条 token_to_code 抓包(整包复用 body+头,仅换 paypal-request-id)。
设备指纹(riskData/appInfo/deviceInfo/firstPartyClientId)与请求头(CMID/FPTI/ConsumerApp-Context/UA)取自来源抓包;channel=Web、tenantName=PayPal、redirectUri 为 token_to_code 固定值(可用 query/body 的 returnUrl 覆盖)。返回仅三个字段。
{ "ok": true,
"auth_url": "https://www.paypal.com/signin?intent=nativeWebSSO&...",
"returnUrl": "" }
{ "ok": false, "auth_url": "", "returnUrl": "",
"error": "no_source" } // 失败时多带 error:paypal_container_not_found / no_source / request_failed / paypal_http_401 / no_auth_url 等
特例接口(仅 PayPal)。批量添加备用邮箱:对每个地址发起
update-account-profile,并强制 mandatory_email_confirmation=false(未验证邮箱也会出现在 profile 列表)。
凭据优先读 keychain UserAccessToken(A23AA);会话头取自最近 profile 抓包或
cvk_weblogin_params.json 的 profileHeaders(需先在 PayPal App 打开过资料页一次)。
{ "emails": [ "backup1@example.com", "backup2@example.com" ] }
{ "ok": true,
"results": [
{ "email": "backup1@example.com", "ok": true, "http_status": 200,
"unique_id": "TJY3UWJANW3UE", "confirmed": false, "closure_id": "..." },
{ "email": "bad@x.com", "ok": false, "http_status": 403, "error": "PermissionDenied" }
] }
{ "ok": false, "error": "no_token", "results": [] }
{ "ok": false, "error": "no_profile_session", "hint": "...", "results": [] }
读取某环境 env.plist 内的伪装数据(伪装了哪些项、各项的值)。?record= 缺省为当前激活环境。
{ "record": "...", "isActive": true, "count": 12, "enabledCount": 9,
"fields": [ { "key": "_pinnedDeviceModel", "label": "设备型号",
"value": "iPhone14,3", "enabled": true }, ... ] }
列出指定环境的网络拦截/参数替换规则。name 缺省取当前激活环境。
{ "environment": "...", "count": 2,
"rules": [ { "url": "api.example.com/login", "key": "deviceId", "value": "替换值" }, ... ] }
给指定环境添加拦截规则,支持单条或批量。name 缺省取当前激活环境;每条 url 必填,key/value 可空。
{ "name": "环境名", "url": "api.example.com/login", "key": "deviceId", "value": "替换值" }
// 也支持 query:?name=&url=&key=&value=
{ "name": "环境名", "rules": [ { "url": "api.paypal.com/graphql", "params": { "firstName": "Raji", "lastName": "Ramakrishnan", "isPartial": false } } ] }
// params 值请用 JSON 类型:布尔写 false/true(不要 ""),数字写 123。
// 或旧格式 { "url": "...", "key": "...", "value": "..." };也可直接 POST 数组,环境名取 ?name= 或当前激活环境
{ "environment": "...", "added": 1, "count": 3, "rules": [...] }
| error | 说明 |
|---|---|
url_required | 单条缺 url |
no_valid_rules | 批量里没有有效规则 |
unknown_environment | 环境不存在 |
实时枚举「当前激活环境(即此刻真机)」的 Keychain 条目,经 cvkkcd 跨组实时读取,不读备份文件。目标 App 取持久化的注入预设列表。
{ "record": "...", "count": 8, "targets": ["com.xxx.app", ...],
"items": [ { "agrp": "...", "class": "genp", "classLabel": "通用密码",
"account": "...", "service": "...", "label": "...",
"isSE": false, "bytes": 64, "kind": "...", "value": "...",
"_raw": "" }, ... ] }
// 无注入目标时:{ ..., "error": "no_injection_targets" }
读取 key 过滤名单:命中的 kSecClassKey 条目在备份/恢复时都会跳过。
{ "needles": ["...", "..."] }
覆盖写入 key 过滤名单。
{ "needles": ["needle1", "needle2"] } // 也可直接 POST 一个数组
{ "ok": true, "needles": [...], "error": null }
实时删除单条 keychain 条目。raw 取自 /api/keychain 列表行的 _raw。
{ "raw": "<一条 cvksd1 jsonl>" }
{ "ok": true, "deleted": 1 }
把指定环境分别打包成 <环境名>.tar 写入导出目录(进程内 USTAR 打包)。
{ "names": ["env1", "env2"] } // 也支持 ?name=env 或 {"name":"env"}
{ "exported": ["env1"], "failed": ["env2 (原因)"],
"exportPath": "/var/mobile/Media/CVKShadowKit/export",
"exports": [{ "name": "env1.tar", "size": 12345 }] }
删除指定环境整棵目录。拒绝删除默认环境(原始机器)与当前激活环境。
{ "names": ["env1", "env2"] } // 或查询参数 ?names=env1,env2
{ "deleted": ["env1"], "failed": ["env2 (...)"], "current": "...", "environments": [...] }
扫描导入目录下所有 .tar / .tar.gz / .tgz,逐个解压到环境目录(如 aaa.tar → data/aaa/),同名旧环境会被覆盖。请求体为空。
{ "imported": ["aaa"], "failed": [], "importPath": "...", "environments": [...] }
上传单个归档(.tar / .tar.gz / .tgz)并立即解压成环境。请求体为原始归档字节(非 multipart),文件名取查询参数 name。支持大文件流式接收。
curl -X POST --data-binary @aaa.tar \ "http://<设备IP>:<端口>/api/upload?name=aaa.tar"
{ "saved": "aaa.tar", "bytes": 1024, "imported": "aaa", "ok": true,
"error": null, "environments": [...] }
为某环境构建/查找匹配的导出归档(用于下载前拿到归档名与体积)。
{ "name": "环境名" }
{ "bundle": "环境名.tar", "size": 12345, "members": ["..."] }
// 无匹配时:{ "error": "no_match" }
删除导出目录中的某个归档文件。
{ "name": "环境名.tar" }
{ "ok": true, "error": null }
从另一台运行本服务的设备直接拉取并导入指定环境(设备到设备迁移)。
{ "ip": "192.168.x.x", "name": "环境名" }
{ "ok": true, "host": "192.168.x.x", "imported": ["环境名"],
"failed": [], "environments": [...] }
// 失败:{ "ok": false, "error": "...", "conflict_env": "...", ... }
查询正在进行的远程导入进度快照(供前端轮询)。
以 /rootfs/var/mobile/Media/CVKShadowKit 为根列目录(可见 data/export/import)。path 缺省为根;目录在前、按名排序。
{ "path": "data", "items": [ { "name": "原始机器", "isDirectory": true, "size": 0 }, ... ] }
下载浏览根目录下的某个文件(带越界防护,application/octet-stream)。
列出某环境目录下的文件/子目录。path 可省略(即环境根)。
[ { "name": "appData", "isDirectory": true, "size": 0 },
{ "name": "env.plist", "isDirectory": false, "size": 512 } ]
下载环境目录中的某个文件(application/octet-stream,带 Content-Disposition)。
下载导出目录或导入目录中的 .tar 文件。
| 参数 | 说明 |
|---|---|
kind | export 或 import |
name | 目标 .tar 文件名(不含路径) |
读取手机系统粘贴板当前文本。App 在后台时可能返回空串,需把 App 置于前台再读。
{
"ok": true,
"text": "hello",
"length": 5,
"changeCount": 12
}
写入手机系统粘贴板。JSON {"text":"..."} 或 raw UTF-8 纯文本;受通用 64KB body 上限约束。
{ "text": "从电脑写入手机" }
{
"ok": true,
"length": 8,
"changeCount": 13
}