// ==UserScript==
// @name 编程猫 CoCo 作品分享审核绕过
// @namespace https://s-lightning.github.io/
// @version 0.1.11
// @description 绕过 CoCo 作品分享的审核机制,让他人可以看到你分享的作品,请低调使用
// @author SLIGHTNING
// @match http://coco.codemao.cn/editor/*
// @match https://coco.codemao.cn/editor/*
// @icon https://coco.codemao.cn/favicon.ico
// @grant none
// @license AGPL-3.0
// ==/UserScript==
(function() {
"use strict";
;(function() {
if (location.pathname != "/editor/") {
return
}
let originalFetch = fetch
fetch = async function(input, init) {
let response = await originalFetch(input, init)
if (input == "https://static.codemao.cn/coco/whitelist.json") {
try {
let workID = location.search.match(/(?<=(\?|&)workId=)[0-9]+(?=$|&)/)
if (workID == null) {
throw new Error("获取作品 ID 失败,可能因为作品未保存到云端,请将作品保存到云端后再尝试。")
}
workID = Number(workID[0])
if (workID == 0 || isNaN(workID)) {
throw new Error("获取作品 ID 失败,可能因为作品未保存到云端,请将作品保存到云端后再尝试。")
}
let whiteList = await response.json()
whiteList.push(workID)
return new Response(JSON.stringify(whiteList), {
...response
})
} catch (error) {
error.message = `绕过审核失败:${error.message}`
console.error(error)
return response
}
}
return response
}
})()
function bypassAudit() {
if (location.search.includes("playerBcmUrl")) {
if (!parent.SLIGHTNING_BYPASS_AUDIT_STOP) {
let scriptElement = document.createElement("script")
scriptElement.innerHTML = `(${bypassAudit})()`
parent.document.body.appendChild(scriptElement)
}
return
}
if (window.SLIGHTNING_BYPASS_AUDIT_STOP) {
return
}
window.SLIGHTNING_BYPASS_AUDIT_STOP = true
document.getElementById("editor-iframe")?.remove()
let originalAlert = alert
alert = function(message) {
if (message == "作品审核中,请稍后再试。") {
console.log(message)
} else {
originalAlert.apply(this, arguments)
}
}
let hintElement = document.createElement("div")
hintElement.innerText = "该作品包含未经审核的第三方自定义控件,需要手动点击按钮运行作品。"
Object.assign(hintElement.style, {
width: "100%",
position: "fixed",
top: "0px",
color: "white",
backgroundColor: "#FF000080",
backdropFilter: "blur(16px)",
fontSize: "2em",
textAlign: "center",
zIndex: 1000
})
document.body.appendChild(hintElement)
function start() {
const stringWorkID = location.pathname.split("/").pop()
if (stringWorkID == null) {
alert("绕过审核失败:获取作品 ID 失败。")
return
}
const workID = parseInt(stringWorkID)
const storageKey = `SLIGHTNING_BYPASS_AUDIT_@${workID}_ALLOW_RUN`
localStorage.removeItem(storageKey)
let iframe = document.createElement("iframe")
iframe.src = location.href
Object.assign(iframe.style, {
border: "none",
position: "fixed",
left: "0px",
top: "0px",
width: "100%",
height: "100%",
zIndex: 10000
})
document.body.append(iframe)
let { contentWindow } = iframe
contentWindow.SLIGHTNING_BYPASS_AUDIT_STOP = true
let originalFetch = contentWindow.fetch
contentWindow.fetch = async function(input, init) {
let response = await originalFetch(input, init)
if (/https?:\/\/static.codemao.cn\/coco\/whitelist.json/.test(input.toString())) {
let whiteList = await response.json()
whiteList.push(workID)
return new Response(JSON.stringify(whiteList), response)
} else if (/https?:\/\/creation\.bcmcdn\.com\/716\/appcraft\/JSON_([0-9]|[a-z]|[A-Z])*_[0-9]*.json/.test(input.toString())) {
let work = await response.json()
let { blockCode } = work
let element = contentWindow.document.getElementById("editor-iframe")
let { contentWindow: editorWindow } = element
editorWindow.addEventListener("load", () => {
new editorWindow.Function("blockCode", `(${function (blockCode) {
parent.postMessage({
type: "PLAYER_BLOCK_CODE",
payload: blockCode
}, "http://coco.codemao.cn")
parent.postMessage({
type: "PLAYER_BLOCK_CODE",
payload: blockCode
}, "https://coco.codemao.cn")
}.toString()})(blockCode)`)(blockCode)
contentWindow.document.getElementById("editor-iframe")?.remove()
})
return new Response(JSON.stringify(work), response)
}
return response
}
}
function setStartButton(element) {
let startCoverElement = document.createElement("div")
Object.assign(startCoverElement.style, {
width: "100%",
height: "100%",
position: "absolute",
top: "0px",
zIndex: 100,
backgroundColor: "#00000080",
display: "flex",
alignItems: "center",
justifyContent: "center"
})
let startButton = document.createElement("img")
startButton.src = "https://cdn-community.codemao.cn/community_frontend/asset/play_btn_76b2a.png"
Object.assign(startButton.style, {
width: "96px",
height: "96px",
cursor: "pointer"
})
startCoverElement.append(startButton)
element.append(startCoverElement)
startButton.addEventListener("click", start)
}
let styleElement = document.createElement("style")
styleElement.innerHTML = "#rootPlayer:after { content: none !important; }"
document.body.append(styleElement)
let wrapElement = document.getElementById("webPlayer")
if (wrapElement == null) {
setStartButton(document.getElementById("root"))
} else {
wrapElement = wrapElement.children[0]
setStartButton(wrapElement)
}
}
function modifyReleaseFile(file) {
if (file.unsafeExtensionWidgetList.length == 0) {
return
}
addExtension(file)
}
function addExtension(file) {
file.unsafeExtensionWidgetList.push({
code: `
new Function(\`(\${${
bypassAudit.toString()
}}) ()\`) ()
const types = {
type: "SLIGHTNING_BYPASS_AUDIT_WIDTH",
title: "审核绕过",
icon: "",
isInvisibleWidget: true,
isGlobalWidget: true,
properties: [],
methods: [],
events: []
}
class Widget extends InvisibleWidget {
constructor(props) {
super(props)
}
}
exports.types = types
exports.widget = Widget
//`,
type: "EXTENSION_SLIGHTNING_BYPASS_AUDIT_WIDTH"
})
}
;(function () {
let originalSend = XMLHttpRequest.prototype.send
XMLHttpRequest.prototype.send = function(data) {
if (data instanceof FormData) {
let fileName = data.get("fname"),
originalFile = data.get("file")
if (fileName == "test.json") {
let xhr = this,
xhrArguments = arguments
let reader = new FileReader()
reader.readAsText(originalFile)
reader.onload = async function() {
try {
let fileContent = JSON.parse(this.result)
modifyReleaseFile(fileContent)
let blob = new Blob([JSON.stringify(fileContent)], { type: "text/plain" })
let file = new File([blob], originalFile.name, { type: originalFile.type })
data.set("file", file)
} catch (error) {
console.error(error)
alert(`绕过审核失败:${error.message}`)
}
originalSend.apply(xhr, xhrArguments)
}
} else {
originalSend.apply(this, arguments)
}
} else {
originalSend.apply(this, arguments)
}
}
})()
})()