Spaces:
Running
Running
class ProjectPermissionManager { | |
static permissions = { | |
javascript: true, | |
camera: true, | |
allWebsites: true, | |
cameraPictures: false, | |
scratchSignIn: true, | |
limitedWebsites: {} | |
}; | |
static permissionMessages = { | |
javascript: "use custom code in JavaScript", | |
camera: "turn on your camera", | |
allWebsites: "display all websites", | |
cameraPictures: "take screenshots while your camera is on", | |
scratchSignIn: "sign in with Scratch", | |
limitedWebsite: "display $0", | |
}; | |
static permissionDrawbacks = { | |
javascript: [], | |
camera: [], | |
allWebsites: [], | |
cameraPictures: ["take a screenshot while your camera is visible"], | |
scratchSignIn: [], | |
limitedWebsite: [], | |
}; | |
static requiresCode = []; | |
static disabledPermissions = []; | |
static get skipPermissionRequest() { | |
if (!vm) return false; | |
if (!vm.runtime) return false; | |
return vm.runtime.isProjectPermissionManagerDisabled === true; | |
} | |
static GenerateCode(length) { | |
return Array.from(new Array(length).keys()).map(() => { return Math.round(Math.random() * 9) }).join(""); // generates something like 281964 | |
} | |
static EditPromptForAcceptCheck(string) { | |
return String(string).replace(/ /gmi, "").toLowerCase(); | |
} | |
static RequestPermission(name, ...args) { | |
// packager | |
if (ProjectPermissionManager.skipPermissionRequest === true) return true; | |
if (ProjectPermissionManager.disabledPermissions.includes(name)) return false; | |
if (name == "limitedWebsite") { | |
if (args.length < 1) throw new Error("No URL specified what are you trying to get permission for bro"); | |
if (!ProjectPermissionManager.IsUrlSafe(args[0])) return false; | |
}; | |
// check if we already gave permission to do this | |
if (name == "limitedWebsite") { | |
if (ProjectPermissionManager.permissions.limitedWebsites[args[0]] == true) return true; | |
}; | |
if (ProjectPermissionManager.permissions[name]) return true; | |
let string = `Allow this project to ${ProjectPermissionManager.permissionMessages[name]}?`; | |
for (let i = 0; i < args.length; i++) { | |
const argument = args[i]; | |
string = string.replace(`$${i}`, (ProjectPermissionManager.IsDataUrl(argument) ? "custom website" : String(argument))); | |
} | |
string += `\n\nThis will allow the project to:\n`; | |
ProjectPermissionManager.permissionDrawbacks[name].forEach(drawback => { | |
string += `▪ ${drawback}\n`; | |
}); | |
let acceptCode = "ok"; | |
if (ProjectPermissionManager.requiresCode.includes(name)) { | |
acceptCode = ProjectPermissionManager.GenerateCode(6); | |
}; | |
string += `\nType "${acceptCode}" to allow, or type "stop" to never ask for this permission again.`; | |
const allow = ProjectPermissionManager.EditPromptForAcceptCheck(prompt(string, "")); | |
if (allow == "stop") { | |
// yes this does intentionally disable asking for any specific website after one was rejected | |
ProjectPermissionManager.disabledPermissions.push(name); | |
return false; | |
} | |
const allowed = allow === String(acceptCode); | |
if (name == "limitedWebsite") { | |
if (!allowed) return false; | |
ProjectPermissionManager.permissions.limitedWebsites[args[0]] = true; | |
return true; | |
}; | |
ProjectPermissionManager.permissions[name] = allowed; | |
return allowed; | |
}; | |
static RequestAllPermissions() { | |
// packager | |
if (ProjectPermissionManager.skipPermissionRequest === true) return true; | |
if (ProjectPermissionManager.disabledPermissions.includes("all")) return false; | |
const permissions = []; | |
Object.getOwnPropertyNames(ProjectPermissionManager.permissions).forEach(permissionName => { | |
if (typeof ProjectPermissionManager.permissions[permissionName] != "boolean") return; | |
permissions.push(permissionName); | |
}); | |
let string = `Give all permissions to this project?`; | |
string += `\n\nThis will allow the project to:\n`; | |
permissions.forEach(permissionName => { | |
ProjectPermissionManager.permissionDrawbacks[permissionName].forEach(drawback => { | |
string += `▪ ${drawback}\n`; | |
}); | |
}); | |
const acceptCode = ProjectPermissionManager.GenerateCode(8); | |
string += `\nType "${acceptCode}" to allow, or type "stop" to never ask for all permissions again.`; | |
const allow = ProjectPermissionManager.EditPromptForAcceptCheck(prompt(string, "")); | |
if (allow == "stop") { | |
ProjectPermissionManager.disabledPermissions.push("all"); | |
return false; | |
} | |
const allowed = allow === String(acceptCode); | |
if (!allowed) return false; | |
Object.getOwnPropertyNames(ProjectPermissionManager.permissions).forEach(permissionName => { | |
if (typeof ProjectPermissionManager.permissions[permissionName] != "boolean") return; | |
ProjectPermissionManager.permissions[permissionName] = true; | |
}); | |
return true; | |
} | |
static CanCreateURLObject(url) { | |
let success = true; | |
try { | |
new URL(url); | |
} catch { | |
success = false; | |
} | |
return success; | |
} | |
static IsDataUrl(url) { | |
// if its not a valid url | |
// its probably not a data url | |
if (!this.CanCreateURLObject(url)) return false; | |
// create url object cuz ez to read | |
const urlObject = new URL(url); | |
// now we can just check the protocol | |
return urlObject.protocol === 'data:'; | |
}; | |
static IsUrlSafe(url) { // checks for non-kid friendly urls because that would be a big stinker | |
// we dont know what this is just say yup thas good | |
if (!this.CanCreateURLObject(url)) return false; | |
// custom urls cannot be checked yet, just say its safe for now | |
if (ProjectPermissionManager.IsDataUrl(url)) return true; | |
const urlObject = new URL(url); | |
const origin = urlObject.origin.toLowerCase(); | |
// check origin for stuff | |
let returningValue = true; | |
// obviously this can be bypassed | |
// but it blocks large or well-known sites | |
// from working straight out of the gate | |
// projects with these sites will not be approved anyways | |
if ( | |
origin.includes("xxx") | |
|| origin.includes("adult") | |
|| origin.includes(atob("c2V4")) | |
|| origin.includes(atob("cG9ybg==")) | |
|| origin.includes(atob("Ym9vcnU=")) | |
|| origin.includes(atob("aGVudGFp")) | |
) returningValue = false; | |
// const mainName = link.match(/(?=(\.|\/\/))[^\n]+(?=(\.))/gmi)[0].replace(/(\/\/|)[^\n]+(?=(\.))/gmi, "").replace(/\/\//gmi, "") | |
return returningValue; | |
}; | |
}; | |
module.exports = ProjectPermissionManager; |