From ee61de36f841ae6c90eee6083d69a1f325aae675 Mon Sep 17 00:00:00 2001 From: Logise1123 <88378769+Logise1123@users.noreply.github.com> Date: Mon, 21 Apr 2025 14:55:12 +0200 Subject: [PATCH 1/2] Create firebasedb.js --- extensions/firebasedb.js | 187 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 extensions/firebasedb.js diff --git a/extensions/firebasedb.js b/extensions/firebasedb.js new file mode 100644 index 0000000000..c1805b1cec --- /dev/null +++ b/extensions/firebasedb.js @@ -0,0 +1,187 @@ +// Name: FirebaseDB +// ID: firebasedb +// Description: Extension for online, password-protected Firebase database storage. +// By: Logise +// Original: FirebaseDB +// License: MPL-2.0 + +(function(Scratch) { + 'use strict'; + if (!Scratch.extensions.unsandboxed) throw new Error("FirebaseDB must run unsandboxed"); + const icon = "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIyMDguMDY5MzUiIGhlaWdodD0iMjA4LjA2OTM1IiB2aWV3Qm94PSIwLDAsMjA4LjA2OTM1LDIwOC4wNjkzNSI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTIxNS45NjUzMiwtNzUuOTY1MzMpIj48ZyBzdHJva2U9Im5vbmUiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTIxNS45NjUzMywxODBjMCwtNTcuNDU2NzYgNDYuNTc3OTEsLTEwNC4wMzQ2NyAxMDQuMDM0NjgsLTEwNC4wMzQ2N2M1Ny40NTY3NywwIDEwNC4wMzQ2OCw0Ni41Nzc5MSAxMDQuMDM0NjgsMTA0LjAzNDY4YzAsNTcuNDU2NzYgLTQ2LjU3NzkxLDEwNC4wMzQ2OCAtMTA0LjAzNDY3LDEwNC4wMzQ2OGMtNTcuNDU2NzcsMCAtMTA0LjAzNDY3LC00Ni41Nzc5MSAtMTA0LjAzNDY3LC0xMDQuMDM0Njd6IiBmaWxsPSIjZmVhNjMxIiBzdHJva2Utd2lkdGg9IjAiLz48cGF0aCBkPSJNMjc1LjE0NjI0LDE4Ni4yMDEwNGMwLjE3ODQ3LC0wLjAwMDUgMC4zNTY5NCwtMC4wMDA5OCAwLjU0MDgyLC0wLjAwMTQ5YzAuNTk4NDYsLTAuMDAxMzYgMS4xOTY5MiwtMC4wMDEwMSAxLjc5NTM4LC0wLjAwMDY3YzAuNDMzMjYsLTAuMDAwNjIgMC44NjY1MiwtMC4wMDEzNCAxLjI5OTc4LC0wLjAwMjE2YzEuMTkxMDMsLTAuMDAxOTQgMi4zODIwNSwtMC4wMDIzNyAzLjU3MzA4LC0wLjAwMjU1YzEuMjg0NDIsLTAuMDAwNDUgMi41Njg4NSwtMC4wMDIyNiAzLjg1MzI4LC0wLjAwMzg4YzIuODA4OTYsLTAuMDAzMjYgNS42MTc5MiwtMC4wMDQ3MSA4LjQyNjg4LC0wLjAwNTc3YzEuNzU0MywtMC4wMDA2NiAzLjUwODYsLTAuMDAxNjkgNS4yNjI5LC0wLjAwMjc3YzQuODU4MDcsLTAuMDAyOTMgOS43MTYxNCwtMC4wMDU0MSAxNC41NzQyMSwtMC4wMDYyMmMwLjMxMDkyLC0wLjAwMDA2IDAuNjIxODUsLTAuMDAwMSAwLjk0MjE5LC0wLjAwMDE2YzAuMzExNjcsLTAuMDAwMDYgMC42MjMzMywtMC4wMDAxIDAuOTQ0NDQsLTAuMDAwMTZjMC42MzE1NCwtMC4wMDAxIDEuMjYzMDgsLTAuMDAwMjEgMS44OTQ2MiwtMC4wMDAzMmMwLjMxMzI3LC0wLjAwMDA2IDAuNjI2NTMsLTAuMDAwMSAwLjk0OTI5LC0wLjAwMDE2YzUuMDc0MzQsLTAuMDAwOTUgMTAuMTQ4NjYsLTAuMDA1MTUgMTUuMjIzLC0wLjAxMDc1YzUuMjEwOTgsLTAuMDA1NzEgMTAuNDIxOTQsLTAuMDA4NjkgMTUuNjMyOTMsLTAuMDA4OTdjMi45MjUyNSwtMC4wMDAyMiA1Ljg1MDUsLTAuMDAxNiA4Ljc3NTc2LC0wLjAwNTk3YzIuNDkxMzMsLTAuMDAzNyA0Ljk4MjY0LC0wLjAwNDkzIDcuNDczOTcsLTAuMDAyOTVjMS4yNzA0NywwLjAwMDk0IDIuNTQwOTMsMC4wMDA3MiAzLjgxMTQsLTAuMDAyNjZjMS4xNjQ2OSwtMC4wMDMwNyAyLjMyOTMxLC0wLjAwMjc3IDMuNDk0LDAuMDAwMTRjMC40MTk3NSwwLjAwMDQ3IDAuODM5NSwtMC4wMDAyNiAxLjI1OTI1LC0wLjAwMjM2YzQuNjU3MjYsLTAuMDIxODUgOC44OTI1NiwwLjY5Mzc4IDEyLjM4ODc4LDQuMDY5MjNjMi4yOTkzNiwyLjU4MjY3IDMuMDM5OTUsNC45ODc0MyAzLjAyNzY2LDguMzc0MThjMC4wMDEzNywwLjMyMjEzIDAuMDAzMDUsMC42NDQyNSAwLjAwNSwwLjk2NjM4YzAuMDA0MywwLjg3MDQ4IDAuMDA0MDMsMS43NDA5IDAuMDAyNjYsMi42MTEzOWMtMC4wMDA3NCwwLjcyOTQ4IDAuMDAwNzIsMS40NTg5NCAwLjAwMjE3LDIuMTg4NDFjMC4wMDMzNywxLjcyMzE1IDAuMDAzMDEsMy40NDYyOCAwLjAwMDI3LDUuMTY5NDNjLTAuMDAyNzUsMS43NzA0MyAwLjAwMDYxLDMuNTQwNzcgMC4wMDcwNyw1LjMxMTE5YzAuMDA1MzUsMS41MjU5IDAuMDA2OTEsMy4wNTE3NyAwLjAwNTUxLDQuNTc3NjljLTAuMDAwODEsMC45MDg3MiAtMC4wMDAyNiwxLjgxNzM3IDAuMDAzOTEsMi43MjYwOGMwLjAwMzc2LDAuODU2MDIgMC4wMDI3MiwxLjcxMTkxIC0wLjAwMTc2LDIuNTY3OTFjLTAuMDAxMjksMC40NTg1NiAwLjAwMjEsMC45MTcxMyAwLjAwNTcsMS4zNzU2N2MtMC4wMzE3MiwzLjc2NTQxIC0xLjMwNDM4LDcuMTM1MDYgLTMuODk4ODIsOS44NjYyOGMtMy4zMzE5MSwzLjI0MjAxIC03LjA3ODEsMy43NDA2NiAtMTEuNTMxMzYsMy43MzM3NGMtMC40MzQ1MywwLjAwMTA3IC0wLjg2OTA3LDAuMDAyMzUgLTEuMzAzNiwwLjAwMzgyYy0xLjE5MTIxLDAuMDAzNCAtMi4zODI0MSwwLjAwMzggLTMuNTczNjMsMC4wMDM3Yy0xLjI4NTksMC4wMDAzOSAtMi41NzE4LDAuMDAzNTQgLTMuODU3NjksMC4wMDYzYy0yLjgxMDQ0LDAuMDA1NDkgLTUuNjIwODgsMC4wMDc0IC04LjQzMTMyLDAuMDA4NjFjLTEuNzU1OCwwLjAwMDc5IC0zLjUxMTU5LDAuMDAyMzUgLTUuMjY3MzksMC4wMDQwOWMtNC44NjQwOCwwLjAwNDcxIC05LjcyODE2LDAuMDA4NjUgLTE0LjU5MjI1LDAuMDA5MzRjLTAuNDY2NywwLjAwMDA3IC0wLjQ2NjY5LDAuMDAwMDcgLTAuOTQyODEsMC4wMDAxNGMtMC42MzA3LDAuMDAwMDkgLTEuMjYxNCwwLjAwMDE4IC0xLjg5MjEsMC4wMDAyN2MtMC40Njk2LDAuMDAwMDcgLTAuNDY5NiwwLjAwMDA3IC0wLjk0ODY5LDAuMDAwMTRjLTAuNDcwMTcsMC4wMDAwNyAtMC40NzAxOCwwLjAwMDA3IC0wLjk0OTg1LDAuMDAwMTNjLTUuMDc3ODYsMC4wMDA4NSAtMTAuMTU1NywwLjAwNzM1IC0xNS4yMzM1NSwwLjAxNjM0Yy01LjIxNjk4LDAuMDA5MTYgLTEwLjQzMzk0LDAuMDEzODEgLTE1LjY1MDkzLDAuMDEzODhjLTIuOTI3NjksMC4wMDAxNCAtNS44NTUzNCwwLjAwMjE3IC04Ljc4MzAzLDAuMDA5MTRjLTIuNDkzMTUsMC4wMDU5IC00Ljk4NjI3LDAuMDA3NjQgLTcuNDc5NDIsMC4wMDQwM2MtMS4yNzEwNSwtMC4wMDE3MiAtMi41NDIwMSwtMC4wMDE1MyAtMy44MTMwNSwwLjAwMzk0Yy0xLjE2NTc1LDAuMDA0OTggLTIuMzMxMzYsMC4wMDQzMSAtMy40OTcxLC0wLjAwMDY5Yy0wLjQxOTU4LC0wLjAwMDgzIC0wLjgzOTE3LDAuMDAwMzIgLTEuMjU4NzQsMC4wMDM3N2MtNC4xODkxNCwwLjAzMjI2IC03LjY3MzUxLC0wLjc2MzE1IC0xMC44MTgxMSwtMy43MzcxYy0yLjY5NDQzLC0yLjg1ODQ0IC0zLjQ3MzgsLTYuMjA4NjkgLTMuNDU5NzEsLTEwLjAyOThjLTAuMDAxNjUsLTAuMzE2NjcgLTAuMDAzMywtMC42MzMzNCAtMC4wMDUsLTAuOTU5NmMtMC4wMDQyOCwtMC44NjEgLTAuMDA0MDQsLTEuNzIxOTQgLTAuMDAyNjYsLTIuNTgyOTRjMC4wMDA3NSwtMC43MjIzNCAtMC4wMDA3MywtMS40NDQ2NyAtMC4wMDIxOCwtMi4xNjcwMWMtMC4wMDMzNiwtMS43MDU5OCAtMC4wMDMwMSwtMy40MTE5NCAtMC4wMDAyNiwtNS4xMTc5M2MwLjAwMjc2LC0xLjc1MiAtMC4wMDA2MywtMy41MDM5MiAtMC4wMDcwNywtNS4yNTU5MmMtMC4wMDUzNSwtMS41MTE2MiAtMC4wMDY5MiwtMy4wMjMyMiAtMC4wMDU1MiwtNC41MzQ4NWMwLjAwMDgxLC0wLjg5OTU2IDAuMDAwMjcsLTEuNzk5MDcgLTAuMDAzOSwtMi42OTg2M2MtMC4wMDM3NiwtMC44NDY3NSAtMC4wMDI3MywtMS42OTMzNyAwLjAwMTc2LC0yLjU0MDEyYzAuMDAxMjksLTAuNDUzMzkgLTAuMDAyMDksLTAuOTA2NzkgLTAuMDA1NywtMS4zNjAxNmMwLjAzMDMzLC0zLjU2MDggMS4yMTk2NSwtNi44NTEyMSAzLjczNDQ1LC05LjQyMzE2YzIuNTI0MjYsLTIuMDQ2OTQgNS4wNDYzOCwtMy4xNjU5MiA4LjMwNTA5LC0zLjE1NzQ3eiIgZmlsbD0iI2E0NGMxNSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTMwNi4wNzk4MSwxMTguMDE5NTljMC41NTM5OSwwLjQ0Njg1IDEuMDk4MTIsMC45MDM4OCAxLjYzODA3LDEuMzY3NTdjMC4xMzQyMSwwLjExNTA0IDAuMjY4NDMsMC4yMzAwNiAwLjQwNjcxLDAuMzQ4NThjNC4yODA5NiwzLjcxMzU1IDcuNjIxOTEsOC4zMDUwNCAxMC4xNzMxNiwxMy4zNTcxNWMwLDAuMTU4NyAwLDAuMzE3NCAwLDAuNDgwOWMwLjI2OTYxLC0wLjAwMDY2IDAuNTM5MjMsLTAuMDAxMzMgMC44MTcwMiwtMC4wMDIwMmM2LjU2MDI5LC0wLjAxNjAyIDEzLjEyMDU5LC0wLjAyNzg3IDE5LjY4MDksLTAuMDM1MzZjMy4xNzI1MSwtMC4wMDM3MiA2LjM0NTAyLC0wLjAwODc5IDkuNTE3NTMsLTAuMDE3MDRjMi43NjUxNSwtMC4wMDcxOSA1LjUzMDI5LC0wLjAxMTg0IDguMjk1NDUsLTAuMDEzNDVjMS40NjQxMywtMC4wMDA5NCAyLjkyODI1LC0wLjAwMzE1IDQuMzkyMzcsLTAuMDA4NGMxLjM3ODM1LC0wLjAwNDkgMi43NTY2NywtMC4wMDY0IDQuMTM1MDQsLTAuMDA1MzJjMC41MDU1OCwtMC4wMDAyIDEuMDExMTcsLTAuMDAxNjMgMS41MTY3NCwtMC4wMDQ0YzAuNjkxMTYsLTAuMDAzNTkgMS4zODIxOCwtMC4wMDI3MiAyLjA3MzM1LC0wLjAwMDc1YzAuMTk5MjksLTAuMDAyMSAwLjM5ODU4LC0wLjAwNDIxIDAuNjAzOTEsLTAuMDA2MzdjMy42MDI5NCwwLjAyNzY0IDUuODI4MzUsMi41NzExOSA4LjI4ODc0LDQuODgzMzVjMC41OTUxNSwwLjU1ODY4IDEuMTk3MjMsMS4xMDY2MyAxLjgxMzcyLDEuNjQxODRjMC4xNDM4MiwwLjEyNTUzIDAuMjg3NjQsMC4yNTEwNiAwLjQzNTgyLDAuMzgwNGMwLjM1Nzk0LDAuMzA4MTUgMC43MTkyOCwwLjYxMjM3IDEuMDgyMDMsMC45MTQ4NWMxLjQzNDg3LDEuMjI4NCAyLjUyNzU2LDIuMjQyNTkgMi44NDY5LDQuMTUyNDhjMC4xMDAyMSwxLjU4Mzg3IC0wLjMzMTY2LDIuNzQyOTQgLTEuMjk5LDMuOTg5OTljLTAuNDYzOSwwLjQ1NjI4IC0wLjk0NDA3LDAuODY5NDQgLTEuNDQ5MjksMS4yNzkyOGMtMC40NTU0NywwLjM4NzgyIC0wLjgxODM1LDAuNzgyOCAtMS4xOTU2OCwxLjI0NTQ2Yy0wLjYyMjA3LDAuNzUyNzggLTEuMzA0MDksMS4zNTkxNyAtMi4wNDg1NCwxLjk4ODQyYy0wLjk2MjIyLDAuODY1MjQgLTEuODU4NjYsMS43OTczNCAtMi43NTc2NywyLjcyNzY4Yy0xLjY2NzU3LDEuNzAxIC0zLjE2MTgyLDIuMjY1MzUgLTUuNTE4MTgsMi40NTIzNmMtMy42MDM4NywtMC4xNDI0NSAtNS44MjA2NSwtMi42OTA4MSAtOC4xODAwNCwtNS4xMzAyNmMtMC4xNjIxMSwtMC4xNTY4NCAtMC4zMjQyMiwtMC4zMTM2OCAtMC40OTEyNCwtMC40NzUyN2MtMC4xNDM4MiwtMC4xNDM4MiAtMC4yODc2NCwtMC4yODc2NCAtMC40MzU4MiwtMC40MzU4MmMtMC44MDAwNSwtMC40MzQzMSAtMS4zMzgwMywtMC4yNDYyNSAtMi4yMDkxNSwtMC4wNDUwOWMtMC42MzQ4NiwwLjQ0NTkyIC0wLjYzNDg2LDAuNDQ1OTMgLTEuMTc0MDgsMS4wNTAxYy0wLjIwNjEyLDAuMjEyOTQgLTAuNDEyMjQsMC40MjU4NyAtMC42MjQ2MSwwLjY0NTI3Yy0wLjIwOTg0LDAuMjI0MSAtMC40MTk2OCwwLjQ0ODIgLTAuNjM1ODgsMC42NzkwOWMtMC40MjAzMiwwLjQ0MTI1IC0wLjg0MTcsMC44ODE0OSAtMS4yNjQyNSwxLjMyMDYxYy0wLjE4NDQ2LDAuMTk2MTcgLTAuMzY4OTIsMC4zOTIzMiAtMC41NTg5OCwwLjU5NDQ0Yy0xLjU3MjA0LDEuNDgxNjQgLTMuMjMzNjIsMS44MzAxNCAtNS4zMzk2LDEuNzc4MTRjLTMuMTA1ODgsLTAuMjM1ODkgLTQuNzQxMzcsLTEuOTgzOTMgLTYuNjk5ODgsLTQuMjQ5NGMtMC4zNjg0MiwtMC40MzIzMyAtMC43MzI2MiwtMC44Njc4OSAtMS4wOTYsLTEuMzA0NDZjLTAuNTA3NzksLTAuNjAzNDEgLTEuMDA5MTUsLTEuMTkzNTggLTEuNjAyMzgsLTEuNzE2MDNjLTAuNjA2OTcsLTAuMDU1MzEgLTAuNjA2OTgsLTAuMDU1MzEgLTEuMjAyMjYsMC4yNDA0NWMtMC40MTA2NCwwLjM5MzY4IC0wLjgwNjYxLDAuNzkzOTUgLTEuMjAyMjUsMS4yMDIyNmMtMC4yOTg3NiwwLjI5NzA1IC0wLjU5ODEyLDAuNTkzNSAtMC44OTc5NCwwLjg4OTQ4Yy0wLjMyMTg3LDAuMzE5NjUgLTAuNjQzNzIsMC42MzkzMiAtMC45NjU1NiwwLjk1ODk5Yy0wLjE2NDU4LDAuMTYyNTggLTAuMzI5MTcsMC4zMjUxNCAtMC40OTg3NCwwLjQ5MjY0Yy0wLjE1NjUzLDAuMTU1NzUgLTAuMzEzMDYsMC4zMTE1IC0wLjQ3NDMzLDAuNDcxOThjLTAuMTQyMTksMC4xNDA5NCAtMC4yODQzOSwwLjI4MTg3IC0wLjQzMDg5LDAuNDI3MDhjLTAuMzYyOTUsMC4zNTc5IC0wLjE3Mzg3LDAuMTg3MiAtMS4zMDExMSwxLjU2ODg2Yy0xLjU1NzYzLDAuOTMzODMgLTMuMTc3NDMsMS4xMDU5MyAtNC45NTM2NywxLjEwODMzYy0wLjIzMTQzLDAuMDAzOTcgLTAuNDYyODYsMC4wMDc5NSAtMC43MDEzLDAuMDEyMDVjLTAuNzI5OTQsMC4wMTE1NiAtMS40NTk3NSwwLjAxNjc4IC0yLjE4OTc1LDAuMDIxNzdjLTAuNDk4NzYsMC4wMDY3OCAtMC45OTc1MSwwLjAxMzk4IC0xLjQ5NjI1LDAuMDIxNmMtMS4yMTQ0NSwwLjAxNzY3IC0yLjQyODg1LDAuMDI5NjUgLTMuNjQzNCwwLjAzODUxYy0wLjA3NzM0LDAuMTUyNDIgLTAuMTU0NjcsMC4zMDQ4NCAtMC4yMzQzNSwwLjQ2MTg4Yy0xLjk1MjU0LDMuODM0MDUgLTMuOTIwMDgsNy4zMjQ1NCAtNi43Mzg3NCwxMC41OTg4OGMtMC4xOTA5NCwwLjIyMzQ4IC0wLjM4MTg3LDAuNDQ2OTYgLTAuNTc4NTksMC42NzcyMWMtNi40Njg5Niw3LjM1OTQ3IC0xNS40MjU2OCwxMS4wNjQ4OCAtMjUuMDQxMTEsMTEuNzg4NThjLTkuMjI4ODYsMC41OTAwMSAtMTguNjIyMjMsLTEuOTY3MzggLTI1LjYzNDk1LC04LjA3Mjg1Yy0wLjcyNzAzLC0wLjY0NDY0IC0xLjQyODY3LC0xLjMxMTI4IC0yLjEyNTU2LC0xLjk4ODQyYy0wLjE3OTE1LC0wLjE3Mjk2IC0wLjM1ODMxLC0wLjM0NTkxIC0wLjU0Mjg5LC0wLjUyNDFjLTYuMzUyNCwtNi41ODY4IC05Ljg0MjA4LC0xNS40ODQwNSAtOS44NDEwNywtMjQuNTI5NTZjLTAuMDAwNTMsLTAuNTIxNzMgLTAuMDA0OTEsLTEuMDQzMzQgLTAuMDA5NDYsLTEuNTY1MDVjLTAuMDA4MTIsLTEuOTkxNCAwLjEzMjM1LC0zLjg4NjY0IDAuNTM0OTEsLTUuODQyMjJjMC4wMzI1NywtMC4xODA0NyAwLjA2NTEzLC0wLjM2MDk1IDAuMDk4NjgsLTAuNTQ2ODljMS4zMTQ0NCwtNy4yNzgxNiA0Ljk1Mzk1LC0xNC4xNDYxIDEwLjY2MzQsLTE4Ljk0NDdjMC41MjczMywtMC40NTU2NiAxLjAyODUxLC0wLjkzMzIyIDEuNTMxMDYsLTEuNDE1ODJjMTEuNzIzOTcsLTExLjEzNDI1IDMyLjIzNjE2LC0xMS4xNzI5OSA0NC43Mzg5MiwtMS4zNzk0MnoiIGZpbGw9IiNhNDRjMTUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yODEuODY5MzYsMTM4LjYwOTE4YzIuMzU5MTksMi4wMTg2NSA0LjE1NSw0LjU2NzIgNC41MDI4Myw3LjcyMTY5YzAuMTI3MDUsMy4xNTMwMyAtMC45ODc3MSw1Ljg0MDE2IC0yLjk4NDk4LDguMjA3MjhjLTIuMjAwMzUsMi4zNDIxOSAtNC43Mjg2NywzLjMwNzcxIC03Ljg5OTg1LDMuNDE3OThjLTEuOTMxNDksMC4wMjY5NCAtMy41NzgwOSwtMC4wNTU2NSAtNS4yNzk4OSwtMS4wNTg1NWMtMC4xODA3LC0wLjA5OTE5IC0wLjM2MTQxLC0wLjE5ODM3IC0wLjU0NzU5LC0wLjMwMDU3Yy0yLjcyMDU5LC0xLjYzNyAtNC4xNzE5NCwtMy45MTU4MiAtNS4xMjgzOCwtNi44ODM4NmMtMC42MjQwOCwtMy4zNTUyMSAwLjE5NzM4LC02LjIyOCAyLjA3NDg0LC05LjAyODJjMS42NjIyMSwtMi4xNjQ4MiAzLjk0NTUsLTMuNjY1MzUgNi42NDYyMiwtNC4xNTgxMmMzLjA0NDg5LC0wLjM2NjYxIDYuMTYwNiwwLjE3NDk1IDguNjE2OCwyLjA4MjM1eiIgZmlsbD0iI2ZlYTYzMSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTMzMC44MTM5LDIwNy44MTEwNGMwLjIzNDA2LC0wLjAwMDg0IDAuNDY4MTIsLTAuMDAxNjggMC43MDkyOCwtMC4wMDI1NWMwLjc2ODc2LC0wLjAwMjExIDEuNTM3NDcsLTAuMDAwNzIgMi4zMDYyMywwLjAwMDkxYzAuNTM3MTMsLTAuMDAwMzMgMS4wNzQyNiwtMC4wMDA3OSAxLjYxMTM5LC0wLjAwMTRjMS4xMjM3NiwtMC4wMDA3MSAyLjI0NzUyLDAuMDAwMzIgMy4zNzEyOCwwLjAwMjU3YzEuNDM3NTQsMC4wMDI3NCAyLjg3NTAyLDAuMDAxMTYgNC4zMTI1NSwtMC4wMDE3MmMxLjEwODU2LC0wLjAwMTc0IDIuMjE3MTIsLTAuMDAxMTkgMy4zMjU2OCwwLjAwMDA2YzAuNTI5OTQsMC4wMDAzMiAxLjA1OTg3LC0wLjAwMDA3IDEuNTg5ODEsLTAuMDAxMTljMC43NDE2OSwtMC4wMDEyMyAxLjQ4MzMxLDAuMDAwNjUgMi4yMjQ5OSwwLjAwMzMyYzAuMjE3MTUsLTAuMDAwOTggMC40MzQzLC0wLjAwMTk0IDAuNjU4MDMsLTAuMDAyOTVjMi4wNzQ5OCwwLjAxMzc4IDMuNjU2ODYsMC4yOTc2OCA1LjE5NzgsMS43NjljMS4wNTExOCwxLjE4NDEgMS4yNTYwMywyLjQwNTA1IDEuMTk1NjgsMy45MzQ1N2MtMC4yMDIyNywxLjg4NjkxIC0wLjc3MTExLDIuOTM5MTkgLTIuMjQ0ODQsNC4xNDQ5N2MtMC43NTQ3NSwwLjUxMTI4IC0xLjM4NzgzLDAuNTg2OTIgLTIuMjc0MjksMC41OTMwNWMtMC4yMjI3OCwwLjAwMjA3IC0wLjQ0NTU4LDAuMDA0MTMgLTAuNjc1MTEsMC4wMDYyNmMtMC4zNjU5MywwLjAwMTUzIC0wLjM2NTkzLDAuMDAxNTQgLTAuNzM5MjYsMC4wMDMxMWMtMC4yNTczNCwwLjAwMTk3IC0wLjUxNDY4LDAuMDAzOTMgLTAuNzc5ODEsMC4wMDU5NmMtMC44NTMzNCwwLjAwNTk4IC0xLjcwNjY3LDAuMDA5OTUgLTIuNTYwMDMsMC4wMTM0MWMtMC4yOTE0LDAuMDAxMjggLTAuNTgyOCwwLjAwMjU2IC0wLjg4MzAzLDAuMDAzODhjLTEuNTQyNTcsMC4wMDY0MyAtMy4wODUxMiwwLjAxMTA5IC00LjYyNzY5LDAuMDE0NTZjLTEuNTkyNiwwLjAwNCAtMy4xODUwNywwLjAxNDc3IC00Ljc3NzYzLDAuMDI3MDJjLTEuMjI1MSwwLjAwODA5IC0yLjQ1MDE4LDAuMDEwODcgLTMuNjc1MywwLjAxMjIzYy0wLjU4Njk5LDAuMDAxNjEgLTEuMTczOTgsMC4wMDUyNyAtMS43NjA5NSwwLjAxMTAzYy0wLjgyMjUxLDAuMDA3NjEgLTEuNjQ0NywwLjAwNzYxIC0yLjQ2NzIzLDAuMDA1ODNjLTAuMjQxNTMsMC4wMDM5NCAtMC40ODMwNSwwLjAwNzg5IC0wLjczMTg5LDAuMDExOTZjLTEuNTg2NjgsLTAuMDE0MDMgLTIuNjE2MzksLTAuMzQwNDEgLTMuODQ4NzIsLTEuMzU0NTFjLTEuMTgyOTEsLTEuMjE0MDMgLTEuNDcwNjcsLTIuMzk4MiAtMS41NDc5LC00LjA1NzYxYzAuMDMwNzgsLTEuNjU2MjQgMC41NTI1OCwtMi41NjQ5NSAxLjY0MDg5LC0zLjc2MzYzYzEuNTA3ODYsLTEuNDI1MjMgMy41MDMyMiwtMS4zODY4NiA1LjQ1MDA4LC0xLjM3ODEzeiIgZmlsbD0iI2ZlYTczMSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTMwOC43MDk3NSwyMTguOTc5MTFjMS4xOTU4MSwxLjAzMjYgMS44MzMwNywyLjYzMTY5IDEuOTY4Nyw0LjE3Nzg1Yy0wLjAzMDE3LDEuNDkyMzEgLTAuNDkxNDMsMi44NjQ1MiAtMS40OTUzMSwzLjk4MTUzYy0xLjc1ODczLDEuNTc4MjYgLTMuMTc2NjUsMS44MjQ3OCAtNS40OTkzOSwxLjc1OTI0Yy0xLjM0NzYyLC0wLjA5NTA5IC0yLjI1NjEzLC0wLjU2MDE3IC0zLjE3OTQsLTEuNTQ3OWMtMS4zNTM5OSwtMS43NDUwNyAtMS42NzIzOSwtMy4zMzc3MyAtMS40NDI3MSwtNS41MzAzOGMwLjQ2NjQ1LC0xLjU2MjgzIDEuMjU5OTUsLTIuNjc5MjkgMi42MjE0OSwtMy41Nzc2NWMyLjQyMDYzLC0xLjI5MzcgNC44NDk4MSwtMC43ODY0NiA3LjAyNjYzLDAuNzM3MzJ6IiBmaWxsPSIjZmRhNzMxIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMzA3LjYxMjY5LDE5OC44NzEzN2MxLjIwMzEzLDAuNzM2NTYgMi4yNDYyLDEuOTA4NDcgMi43NTAxNiwzLjIzMTA3YzAuMTg4NDIsMS44MzI2NCAwLjM3NTQxLDMuODU1OTEgLTAuODA5NjQsNS4zODI5MmMtMS42NTkxMywxLjYzOTI5IC0yLjkxMzgyLDIuMTQyMjMgLTUuMjU2OTQsMi4xNDcyN2MtMS41MjkyLC0wLjAyOTg5IC0yLjU4NDExLC0wLjMyMDQ3IC0zLjY3NTQ1LC0xLjM5Nzc0Yy0xLjM0NzYzLC0xLjU1Mjg3IC0xLjYzNzY4LC0yLjc5MDY1IC0xLjYxMDg0LC00Ljc5NDk0YzAuMTA2NTEsLTEuMjcwMzYgMC40OTcyMiwtMi4yMDA5MyAxLjI5OSwtMy4xODU5OGMwLjIyMzE3LC0wLjE4MzQ5IDAuNDQ2MzQsLTAuMzY2OTkgMC42NzYyNywtMC41NTYwNWMwLjEyNDkxLC0wLjExMjIgMC4yNDk4MiwtMC4yMjQ0MSAwLjM3ODUyLC0wLjM0MDAxYzEuNjk0ODUsLTEuMzE2MTcgNC4zMTY3OCwtMS4zNDI3OCA2LjI0ODkyLC0wLjQ4NjU0eiIgZmlsbD0iI2ZlYTczMSIgc3Ryb2tlLXdpZHRoPSIxIi8+PC9nPjwvZz48L3N2Zz4="; + + class FirebaseDB { + constructor() { + this.api = "https://guessthepin-2fe64-default-rtdb.europe-west1.firebasedatabase.app"; + } + + getInfo() { + return { + id: "FirebaseDB", + name: "Firebase DB", + color1: "#fea631", + menuIconURI: icon, + blocks: [ + {blockType: Scratch.BlockType.LABEL, text: "Made by @logise on Discord"}, + { + opcode: "setKey", + blockType: Scratch.BlockType.COMMAND, + text: "set key [KEY] to value [VALUE]", + arguments: { + KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" }, + VALUE: { type: Scratch.ArgumentType.STRING, defaultValue: "value" } + } + }, + { + opcode: "getKey", + blockType: Scratch.BlockType.REPORTER, + text: "get key [KEY]", + arguments: { + KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" } + } + }, + {blockType: Scratch.BlockType.LABEL, text: "Password Blocks:"}, + { + opcode: "setKeyWithPassword", + blockType: Scratch.BlockType.COMMAND, + text: "set key [KEY] to value [VALUE] with password [PASSWORD]", + arguments: { + KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" }, + VALUE: { type: Scratch.ArgumentType.STRING, defaultValue: "value" }, + PASSWORD: { type: Scratch.ArgumentType.STRING, defaultValue: "password" } + } + }, + { + opcode: "getKeyWithPassword", + blockType: Scratch.BlockType.REPORTER, + text: "get key [KEY] with password [PASSWORD]", + arguments: { + KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" }, + PASSWORD: { type: Scratch.ArgumentType.STRING, defaultValue: "password" } + } + }, + { + opcode: "checkPassword", + blockType: Scratch.BlockType.BOOLEAN, + text: "check if password [PASSWORD] is valid for key [KEY]", + arguments: { + PASSWORD: { type: Scratch.ArgumentType.STRING, defaultValue: "password" }, + KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" } + } + } + ] + }; + } + + async delay() { + const d = Math.random() * 500; + return new Promise(r => setTimeout(r, d)); + } + + async setKey(args) { + await this.delay(); + const { KEY, VALUE } = args; + if (VALUE.length > 8000) return; + await fetch(`${this.api}/pin/${encodeURIComponent(KEY)}.json`, { + method: "PUT", + body: JSON.stringify(VALUE) + }); + } + + async getKey(args) { + await this.delay(); + const { KEY } = args; + const res = await fetch(`${this.api}/pin/${encodeURIComponent(KEY)}.json`); + const data = await res.json(); + return data ?? ""; + } + + async deriveKey(password, salt) { + const enc = new TextEncoder(); + const keyMaterial = await crypto.subtle.importKey( + "raw", enc.encode(password), "PBKDF2", false, ["deriveKey"] + ); + return await crypto.subtle.deriveKey( + { + name: "PBKDF2", + salt, + iterations: 100000, + hash: "SHA-256" + }, + keyMaterial, + { name: "AES-GCM", length: 256 }, + false, + ["encrypt", "decrypt"] + ); + } + + async setKeyWithPassword(args) { + await this.delay(); + const { KEY, VALUE, PASSWORD } = args; + if (VALUE.length > 8000) return; + + const enc = new TextEncoder(); + const iv = crypto.getRandomValues(new Uint8Array(12)); + const salt = crypto.getRandomValues(new Uint8Array(16)); + const key = await this.deriveKey(PASSWORD, salt); + const encrypted = await crypto.subtle.encrypt( + { name: "AES-GCM", iv }, key, enc.encode(VALUE) + ); + + const fullPackage = { + iv: Array.from(iv), + salt: Array.from(salt), + data: Array.from(new Uint8Array(encrypted)) + }; + + await fetch(`${this.api}/cypher/${encodeURIComponent(KEY)}.json`, { + method: "PUT", + body: JSON.stringify(fullPackage) + }); + } + + async getKeyWithPassword(args) { + await this.delay(); + const { KEY, PASSWORD } = args; + + const res = await fetch(`${this.api}/cypher/${encodeURIComponent(KEY)}.json`); + const encryptedPackage = await res.json(); + if (!encryptedPackage || !encryptedPackage.data || !encryptedPackage.iv || !encryptedPackage.salt) return ""; + + try { + const iv = new Uint8Array(encryptedPackage.iv); + const salt = new Uint8Array(encryptedPackage.salt); + const data = new Uint8Array(encryptedPackage.data); + const key = await this.deriveKey(PASSWORD, salt); + const decrypted = await crypto.subtle.decrypt( + { name: "AES-GCM", iv }, key, data + ); + return new TextDecoder().decode(decrypted); + } catch (e) { + return ""; + } + } + + async checkPassword(args) { + await this.delay(); + const { KEY, PASSWORD } = args; + + const res = await fetch(`${this.api}/cypher/${encodeURIComponent(KEY)}.json`); + const encryptedPackage = await res.json(); + if (!encryptedPackage || !encryptedPackage.data || !encryptedPackage.iv || !encryptedPackage.salt) return false; + + try { + const iv = new Uint8Array(encryptedPackage.iv); + const salt = new Uint8Array(encryptedPackage.salt); + const data = new Uint8Array(encryptedPackage.data); + const key = await this.deriveKey(PASSWORD, salt); + await crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, data); + return true; + } catch (e) { + return false; + } + } + } + + Scratch.extensions.register(new FirebaseDB()); +})(Scratch); From 811b05937dc22c1cb93c41af86acfa96ab267181 Mon Sep 17 00:00:00 2001 From: "DangoCat[bot]" Date: Mon, 21 Apr 2025 14:04:56 +0000 Subject: [PATCH 2/2] [Automated] Format code --- extensions/firebasedb.js | 401 ++++++++++++++++++++++----------------- 1 file changed, 224 insertions(+), 177 deletions(-) diff --git a/extensions/firebasedb.js b/extensions/firebasedb.js index c1805b1cec..29522b3af2 100644 --- a/extensions/firebasedb.js +++ b/extensions/firebasedb.js @@ -5,183 +5,230 @@ // Original: FirebaseDB // License: MPL-2.0 -(function(Scratch) { - 'use strict'; - if (!Scratch.extensions.unsandboxed) throw new Error("FirebaseDB must run unsandboxed"); - const icon = "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIyMDguMDY5MzUiIGhlaWdodD0iMjA4LjA2OTM1IiB2aWV3Qm94PSIwLDAsMjA4LjA2OTM1LDIwOC4wNjkzNSI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTIxNS45NjUzMiwtNzUuOTY1MzMpIj48ZyBzdHJva2U9Im5vbmUiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTIxNS45NjUzMywxODBjMCwtNTcuNDU2NzYgNDYuNTc3OTEsLTEwNC4wMzQ2NyAxMDQuMDM0NjgsLTEwNC4wMzQ2N2M1Ny40NTY3NywwIDEwNC4wMzQ2OCw0Ni41Nzc5MSAxMDQuMDM0NjgsMTA0LjAzNDY4YzAsNTcuNDU2NzYgLTQ2LjU3NzkxLDEwNC4wMzQ2OCAtMTA0LjAzNDY3LDEwNC4wMzQ2OGMtNTcuNDU2NzcsMCAtMTA0LjAzNDY3LC00Ni41Nzc5MSAtMTA0LjAzNDY3LC0xMDQuMDM0Njd6IiBmaWxsPSIjZmVhNjMxIiBzdHJva2Utd2lkdGg9IjAiLz48cGF0aCBkPSJNMjc1LjE0NjI0LDE4Ni4yMDEwNGMwLjE3ODQ3LC0wLjAwMDUgMC4zNTY5NCwtMC4wMDA5OCAwLjU0MDgyLC0wLjAwMTQ5YzAuNTk4NDYsLTAuMDAxMzYgMS4xOTY5MiwtMC4wMDEwMSAxLjc5NTM4LC0wLjAwMDY3YzAuNDMzMjYsLTAuMDAwNjIgMC44NjY1MiwtMC4wMDEzNCAxLjI5OTc4LC0wLjAwMjE2YzEuMTkxMDMsLTAuMDAxOTQgMi4zODIwNSwtMC4wMDIzNyAzLjU3MzA4LC0wLjAwMjU1YzEuMjg0NDIsLTAuMDAwNDUgMi41Njg4NSwtMC4wMDIyNiAzLjg1MzI4LC0wLjAwMzg4YzIuODA4OTYsLTAuMDAzMjYgNS42MTc5MiwtMC4wMDQ3MSA4LjQyNjg4LC0wLjAwNTc3YzEuNzU0MywtMC4wMDA2NiAzLjUwODYsLTAuMDAxNjkgNS4yNjI5LC0wLjAwMjc3YzQuODU4MDcsLTAuMDAyOTMgOS43MTYxNCwtMC4wMDU0MSAxNC41NzQyMSwtMC4wMDYyMmMwLjMxMDkyLC0wLjAwMDA2IDAuNjIxODUsLTAuMDAwMSAwLjk0MjE5LC0wLjAwMDE2YzAuMzExNjcsLTAuMDAwMDYgMC42MjMzMywtMC4wMDAxIDAuOTQ0NDQsLTAuMDAwMTZjMC42MzE1NCwtMC4wMDAxIDEuMjYzMDgsLTAuMDAwMjEgMS44OTQ2MiwtMC4wMDAzMmMwLjMxMzI3LC0wLjAwMDA2IDAuNjI2NTMsLTAuMDAwMSAwLjk0OTI5LC0wLjAwMDE2YzUuMDc0MzQsLTAuMDAwOTUgMTAuMTQ4NjYsLTAuMDA1MTUgMTUuMjIzLC0wLjAxMDc1YzUuMjEwOTgsLTAuMDA1NzEgMTAuNDIxOTQsLTAuMDA4NjkgMTUuNjMyOTMsLTAuMDA4OTdjMi45MjUyNSwtMC4wMDAyMiA1Ljg1MDUsLTAuMDAxNiA4Ljc3NTc2LC0wLjAwNTk3YzIuNDkxMzMsLTAuMDAzNyA0Ljk4MjY0LC0wLjAwNDkzIDcuNDczOTcsLTAuMDAyOTVjMS4yNzA0NywwLjAwMDk0IDIuNTQwOTMsMC4wMDA3MiAzLjgxMTQsLTAuMDAyNjZjMS4xNjQ2OSwtMC4wMDMwNyAyLjMyOTMxLC0wLjAwMjc3IDMuNDk0LDAuMDAwMTRjMC40MTk3NSwwLjAwMDQ3IDAuODM5NSwtMC4wMDAyNiAxLjI1OTI1LC0wLjAwMjM2YzQuNjU3MjYsLTAuMDIxODUgOC44OTI1NiwwLjY5Mzc4IDEyLjM4ODc4LDQuMDY5MjNjMi4yOTkzNiwyLjU4MjY3IDMuMDM5OTUsNC45ODc0MyAzLjAyNzY2LDguMzc0MThjMC4wMDEzNywwLjMyMjEzIDAuMDAzMDUsMC42NDQyNSAwLjAwNSwwLjk2NjM4YzAuMDA0MywwLjg3MDQ4IDAuMDA0MDMsMS43NDA5IDAuMDAyNjYsMi42MTEzOWMtMC4wMDA3NCwwLjcyOTQ4IDAuMDAwNzIsMS40NTg5NCAwLjAwMjE3LDIuMTg4NDFjMC4wMDMzNywxLjcyMzE1IDAuMDAzMDEsMy40NDYyOCAwLjAwMDI3LDUuMTY5NDNjLTAuMDAyNzUsMS43NzA0MyAwLjAwMDYxLDMuNTQwNzcgMC4wMDcwNyw1LjMxMTE5YzAuMDA1MzUsMS41MjU5IDAuMDA2OTEsMy4wNTE3NyAwLjAwNTUxLDQuNTc3NjljLTAuMDAwODEsMC45MDg3MiAtMC4wMDAyNiwxLjgxNzM3IDAuMDAzOTEsMi43MjYwOGMwLjAwMzc2LDAuODU2MDIgMC4wMDI3MiwxLjcxMTkxIC0wLjAwMTc2LDIuNTY3OTFjLTAuMDAxMjksMC40NTg1NiAwLjAwMjEsMC45MTcxMyAwLjAwNTcsMS4zNzU2N2MtMC4wMzE3MiwzLjc2NTQxIC0xLjMwNDM4LDcuMTM1MDYgLTMuODk4ODIsOS44NjYyOGMtMy4zMzE5MSwzLjI0MjAxIC03LjA3ODEsMy43NDA2NiAtMTEuNTMxMzYsMy43MzM3NGMtMC40MzQ1MywwLjAwMTA3IC0wLjg2OTA3LDAuMDAyMzUgLTEuMzAzNiwwLjAwMzgyYy0xLjE5MTIxLDAuMDAzNCAtMi4zODI0MSwwLjAwMzggLTMuNTczNjMsMC4wMDM3Yy0xLjI4NTksMC4wMDAzOSAtMi41NzE4LDAuMDAzNTQgLTMuODU3NjksMC4wMDYzYy0yLjgxMDQ0LDAuMDA1NDkgLTUuNjIwODgsMC4wMDc0IC04LjQzMTMyLDAuMDA4NjFjLTEuNzU1OCwwLjAwMDc5IC0zLjUxMTU5LDAuMDAyMzUgLTUuMjY3MzksMC4wMDQwOWMtNC44NjQwOCwwLjAwNDcxIC05LjcyODE2LDAuMDA4NjUgLTE0LjU5MjI1LDAuMDA5MzRjLTAuNDY2NywwLjAwMDA3IC0wLjQ2NjY5LDAuMDAwMDcgLTAuOTQyODEsMC4wMDAxNGMtMC42MzA3LDAuMDAwMDkgLTEuMjYxNCwwLjAwMDE4IC0xLjg5MjEsMC4wMDAyN2MtMC40Njk2LDAuMDAwMDcgLTAuNDY5NiwwLjAwMDA3IC0wLjk0ODY5LDAuMDAwMTRjLTAuNDcwMTcsMC4wMDAwNyAtMC40NzAxOCwwLjAwMDA3IC0wLjk0OTg1LDAuMDAwMTNjLTUuMDc3ODYsMC4wMDA4NSAtMTAuMTU1NywwLjAwNzM1IC0xNS4yMzM1NSwwLjAxNjM0Yy01LjIxNjk4LDAuMDA5MTYgLTEwLjQzMzk0LDAuMDEzODEgLTE1LjY1MDkzLDAuMDEzODhjLTIuOTI3NjksMC4wMDAxNCAtNS44NTUzNCwwLjAwMjE3IC04Ljc4MzAzLDAuMDA5MTRjLTIuNDkzMTUsMC4wMDU5IC00Ljk4NjI3LDAuMDA3NjQgLTcuNDc5NDIsMC4wMDQwM2MtMS4yNzEwNSwtMC4wMDE3MiAtMi41NDIwMSwtMC4wMDE1MyAtMy44MTMwNSwwLjAwMzk0Yy0xLjE2NTc1LDAuMDA0OTggLTIuMzMxMzYsMC4wMDQzMSAtMy40OTcxLC0wLjAwMDY5Yy0wLjQxOTU4LC0wLjAwMDgzIC0wLjgzOTE3LDAuMDAwMzIgLTEuMjU4NzQsMC4wMDM3N2MtNC4xODkxNCwwLjAzMjI2IC03LjY3MzUxLC0wLjc2MzE1IC0xMC44MTgxMSwtMy43MzcxYy0yLjY5NDQzLC0yLjg1ODQ0IC0zLjQ3MzgsLTYuMjA4NjkgLTMuNDU5NzEsLTEwLjAyOThjLTAuMDAxNjUsLTAuMzE2NjcgLTAuMDAzMywtMC42MzMzNCAtMC4wMDUsLTAuOTU5NmMtMC4wMDQyOCwtMC44NjEgLTAuMDA0MDQsLTEuNzIxOTQgLTAuMDAyNjYsLTIuNTgyOTRjMC4wMDA3NSwtMC43MjIzNCAtMC4wMDA3MywtMS40NDQ2NyAtMC4wMDIxOCwtMi4xNjcwMWMtMC4wMDMzNiwtMS43MDU5OCAtMC4wMDMwMSwtMy40MTE5NCAtMC4wMDAyNiwtNS4xMTc5M2MwLjAwMjc2LC0xLjc1MiAtMC4wMDA2MywtMy41MDM5MiAtMC4wMDcwNywtNS4yNTU5MmMtMC4wMDUzNSwtMS41MTE2MiAtMC4wMDY5MiwtMy4wMjMyMiAtMC4wMDU1MiwtNC41MzQ4NWMwLjAwMDgxLC0wLjg5OTU2IDAuMDAwMjcsLTEuNzk5MDcgLTAuMDAzOSwtMi42OTg2M2MtMC4wMDM3NiwtMC44NDY3NSAtMC4wMDI3MywtMS42OTMzNyAwLjAwMTc2LC0yLjU0MDEyYzAuMDAxMjksLTAuNDUzMzkgLTAuMDAyMDksLTAuOTA2NzkgLTAuMDA1NywtMS4zNjAxNmMwLjAzMDMzLC0zLjU2MDggMS4yMTk2NSwtNi44NTEyMSAzLjczNDQ1LC05LjQyMzE2YzIuNTI0MjYsLTIuMDQ2OTQgNS4wNDYzOCwtMy4xNjU5MiA4LjMwNTA5LC0zLjE1NzQ3eiIgZmlsbD0iI2E0NGMxNSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTMwNi4wNzk4MSwxMTguMDE5NTljMC41NTM5OSwwLjQ0Njg1IDEuMDk4MTIsMC45MDM4OCAxLjYzODA3LDEuMzY3NTdjMC4xMzQyMSwwLjExNTA0IDAuMjY4NDMsMC4yMzAwNiAwLjQwNjcxLDAuMzQ4NThjNC4yODA5NiwzLjcxMzU1IDcuNjIxOTEsOC4zMDUwNCAxMC4xNzMxNiwxMy4zNTcxNWMwLDAuMTU4NyAwLDAuMzE3NCAwLDAuNDgwOWMwLjI2OTYxLC0wLjAwMDY2IDAuNTM5MjMsLTAuMDAxMzMgMC44MTcwMiwtMC4wMDIwMmM2LjU2MDI5LC0wLjAxNjAyIDEzLjEyMDU5LC0wLjAyNzg3IDE5LjY4MDksLTAuMDM1MzZjMy4xNzI1MSwtMC4wMDM3MiA2LjM0NTAyLC0wLjAwODc5IDkuNTE3NTMsLTAuMDE3MDRjMi43NjUxNSwtMC4wMDcxOSA1LjUzMDI5LC0wLjAxMTg0IDguMjk1NDUsLTAuMDEzNDVjMS40NjQxMywtMC4wMDA5NCAyLjkyODI1LC0wLjAwMzE1IDQuMzkyMzcsLTAuMDA4NGMxLjM3ODM1LC0wLjAwNDkgMi43NTY2NywtMC4wMDY0IDQuMTM1MDQsLTAuMDA1MzJjMC41MDU1OCwtMC4wMDAyIDEuMDExMTcsLTAuMDAxNjMgMS41MTY3NCwtMC4wMDQ0YzAuNjkxMTYsLTAuMDAzNTkgMS4zODIxOCwtMC4wMDI3MiAyLjA3MzM1LC0wLjAwMDc1YzAuMTk5MjksLTAuMDAyMSAwLjM5ODU4LC0wLjAwNDIxIDAuNjAzOTEsLTAuMDA2MzdjMy42MDI5NCwwLjAyNzY0IDUuODI4MzUsMi41NzExOSA4LjI4ODc0LDQuODgzMzVjMC41OTUxNSwwLjU1ODY4IDEuMTk3MjMsMS4xMDY2MyAxLjgxMzcyLDEuNjQxODRjMC4xNDM4MiwwLjEyNTUzIDAuMjg3NjQsMC4yNTEwNiAwLjQzNTgyLDAuMzgwNGMwLjM1Nzk0LDAuMzA4MTUgMC43MTkyOCwwLjYxMjM3IDEuMDgyMDMsMC45MTQ4NWMxLjQzNDg3LDEuMjI4NCAyLjUyNzU2LDIuMjQyNTkgMi44NDY5LDQuMTUyNDhjMC4xMDAyMSwxLjU4Mzg3IC0wLjMzMTY2LDIuNzQyOTQgLTEuMjk5LDMuOTg5OTljLTAuNDYzOSwwLjQ1NjI4IC0wLjk0NDA3LDAuODY5NDQgLTEuNDQ5MjksMS4yNzkyOGMtMC40NTU0NywwLjM4NzgyIC0wLjgxODM1LDAuNzgyOCAtMS4xOTU2OCwxLjI0NTQ2Yy0wLjYyMjA3LDAuNzUyNzggLTEuMzA0MDksMS4zNTkxNyAtMi4wNDg1NCwxLjk4ODQyYy0wLjk2MjIyLDAuODY1MjQgLTEuODU4NjYsMS43OTczNCAtMi43NTc2NywyLjcyNzY4Yy0xLjY2NzU3LDEuNzAxIC0zLjE2MTgyLDIuMjY1MzUgLTUuNTE4MTgsMi40NTIzNmMtMy42MDM4NywtMC4xNDI0NSAtNS44MjA2NSwtMi42OTA4MSAtOC4xODAwNCwtNS4xMzAyNmMtMC4xNjIxMSwtMC4xNTY4NCAtMC4zMjQyMiwtMC4zMTM2OCAtMC40OTEyNCwtMC40NzUyN2MtMC4xNDM4MiwtMC4xNDM4MiAtMC4yODc2NCwtMC4yODc2NCAtMC40MzU4MiwtMC40MzU4MmMtMC44MDAwNSwtMC40MzQzMSAtMS4zMzgwMywtMC4yNDYyNSAtMi4yMDkxNSwtMC4wNDUwOWMtMC42MzQ4NiwwLjQ0NTkyIC0wLjYzNDg2LDAuNDQ1OTMgLTEuMTc0MDgsMS4wNTAxYy0wLjIwNjEyLDAuMjEyOTQgLTAuNDEyMjQsMC40MjU4NyAtMC42MjQ2MSwwLjY0NTI3Yy0wLjIwOTg0LDAuMjI0MSAtMC40MTk2OCwwLjQ0ODIgLTAuNjM1ODgsMC42NzkwOWMtMC40MjAzMiwwLjQ0MTI1IC0wLjg0MTcsMC44ODE0OSAtMS4yNjQyNSwxLjMyMDYxYy0wLjE4NDQ2LDAuMTk2MTcgLTAuMzY4OTIsMC4zOTIzMiAtMC41NTg5OCwwLjU5NDQ0Yy0xLjU3MjA0LDEuNDgxNjQgLTMuMjMzNjIsMS44MzAxNCAtNS4zMzk2LDEuNzc4MTRjLTMuMTA1ODgsLTAuMjM1ODkgLTQuNzQxMzcsLTEuOTgzOTMgLTYuNjk5ODgsLTQuMjQ5NGMtMC4zNjg0MiwtMC40MzIzMyAtMC43MzI2MiwtMC44Njc4OSAtMS4wOTYsLTEuMzA0NDZjLTAuNTA3NzksLTAuNjAzNDEgLTEuMDA5MTUsLTEuMTkzNTggLTEuNjAyMzgsLTEuNzE2MDNjLTAuNjA2OTcsLTAuMDU1MzEgLTAuNjA2OTgsLTAuMDU1MzEgLTEuMjAyMjYsMC4yNDA0NWMtMC40MTA2NCwwLjM5MzY4IC0wLjgwNjYxLDAuNzkzOTUgLTEuMjAyMjUsMS4yMDIyNmMtMC4yOTg3NiwwLjI5NzA1IC0wLjU5ODEyLDAuNTkzNSAtMC44OTc5NCwwLjg4OTQ4Yy0wLjMyMTg3LDAuMzE5NjUgLTAuNjQzNzIsMC42MzkzMiAtMC45NjU1NiwwLjk1ODk5Yy0wLjE2NDU4LDAuMTYyNTggLTAuMzI5MTcsMC4zMjUxNCAtMC40OTg3NCwwLjQ5MjY0Yy0wLjE1NjUzLDAuMTU1NzUgLTAuMzEzMDYsMC4zMTE1IC0wLjQ3NDMzLDAuNDcxOThjLTAuMTQyMTksMC4xNDA5NCAtMC4yODQzOSwwLjI4MTg3IC0wLjQzMDg5LDAuNDI3MDhjLTAuMzYyOTUsMC4zNTc5IC0wLjE3Mzg3LDAuMTg3MiAtMS4zMDExMSwxLjU2ODg2Yy0xLjU1NzYzLDAuOTMzODMgLTMuMTc3NDMsMS4xMDU5MyAtNC45NTM2NywxLjEwODMzYy0wLjIzMTQzLDAuMDAzOTcgLTAuNDYyODYsMC4wMDc5NSAtMC43MDEzLDAuMDEyMDVjLTAuNzI5OTQsMC4wMTE1NiAtMS40NTk3NSwwLjAxNjc4IC0yLjE4OTc1LDAuMDIxNzdjLTAuNDk4NzYsMC4wMDY3OCAtMC45OTc1MSwwLjAxMzk4IC0xLjQ5NjI1LDAuMDIxNmMtMS4yMTQ0NSwwLjAxNzY3IC0yLjQyODg1LDAuMDI5NjUgLTMuNjQzNCwwLjAzODUxYy0wLjA3NzM0LDAuMTUyNDIgLTAuMTU0NjcsMC4zMDQ4NCAtMC4yMzQzNSwwLjQ2MTg4Yy0xLjk1MjU0LDMuODM0MDUgLTMuOTIwMDgsNy4zMjQ1NCAtNi43Mzg3NCwxMC41OTg4OGMtMC4xOTA5NCwwLjIyMzQ4IC0wLjM4MTg3LDAuNDQ2OTYgLTAuNTc4NTksMC42NzcyMWMtNi40Njg5Niw3LjM1OTQ3IC0xNS40MjU2OCwxMS4wNjQ4OCAtMjUuMDQxMTEsMTEuNzg4NThjLTkuMjI4ODYsMC41OTAwMSAtMTguNjIyMjMsLTEuOTY3MzggLTI1LjYzNDk1LC04LjA3Mjg1Yy0wLjcyNzAzLC0wLjY0NDY0IC0xLjQyODY3LC0xLjMxMTI4IC0yLjEyNTU2LC0xLjk4ODQyYy0wLjE3OTE1LC0wLjE3Mjk2IC0wLjM1ODMxLC0wLjM0NTkxIC0wLjU0Mjg5LC0wLjUyNDFjLTYuMzUyNCwtNi41ODY4IC05Ljg0MjA4LC0xNS40ODQwNSAtOS44NDEwNywtMjQuNTI5NTZjLTAuMDAwNTMsLTAuNTIxNzMgLTAuMDA0OTEsLTEuMDQzMzQgLTAuMDA5NDYsLTEuNTY1MDVjLTAuMDA4MTIsLTEuOTkxNCAwLjEzMjM1LC0zLjg4NjY0IDAuNTM0OTEsLTUuODQyMjJjMC4wMzI1NywtMC4xODA0NyAwLjA2NTEzLC0wLjM2MDk1IDAuMDk4NjgsLTAuNTQ2ODljMS4zMTQ0NCwtNy4yNzgxNiA0Ljk1Mzk1LC0xNC4xNDYxIDEwLjY2MzQsLTE4Ljk0NDdjMC41MjczMywtMC40NTU2NiAxLjAyODUxLC0wLjkzMzIyIDEuNTMxMDYsLTEuNDE1ODJjMTEuNzIzOTcsLTExLjEzNDI1IDMyLjIzNjE2LC0xMS4xNzI5OSA0NC43Mzg5MiwtMS4zNzk0MnoiIGZpbGw9IiNhNDRjMTUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yODEuODY5MzYsMTM4LjYwOTE4YzIuMzU5MTksMi4wMTg2NSA0LjE1NSw0LjU2NzIgNC41MDI4Myw3LjcyMTY5YzAuMTI3MDUsMy4xNTMwMyAtMC45ODc3MSw1Ljg0MDE2IC0yLjk4NDk4LDguMjA3MjhjLTIuMjAwMzUsMi4zNDIxOSAtNC43Mjg2NywzLjMwNzcxIC03Ljg5OTg1LDMuNDE3OThjLTEuOTMxNDksMC4wMjY5NCAtMy41NzgwOSwtMC4wNTU2NSAtNS4yNzk4OSwtMS4wNTg1NWMtMC4xODA3LC0wLjA5OTE5IC0wLjM2MTQxLC0wLjE5ODM3IC0wLjU0NzU5LC0wLjMwMDU3Yy0yLjcyMDU5LC0xLjYzNyAtNC4xNzE5NCwtMy45MTU4MiAtNS4xMjgzOCwtNi44ODM4NmMtMC42MjQwOCwtMy4zNTUyMSAwLjE5NzM4LC02LjIyOCAyLjA3NDg0LC05LjAyODJjMS42NjIyMSwtMi4xNjQ4MiAzLjk0NTUsLTMuNjY1MzUgNi42NDYyMiwtNC4xNTgxMmMzLjA0NDg5LC0wLjM2NjYxIDYuMTYwNiwwLjE3NDk1IDguNjE2OCwyLjA4MjM1eiIgZmlsbD0iI2ZlYTYzMSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTMzMC44MTM5LDIwNy44MTEwNGMwLjIzNDA2LC0wLjAwMDg0IDAuNDY4MTIsLTAuMDAxNjggMC43MDkyOCwtMC4wMDI1NWMwLjc2ODc2LC0wLjAwMjExIDEuNTM3NDcsLTAuMDAwNzIgMi4zMDYyMywwLjAwMDkxYzAuNTM3MTMsLTAuMDAwMzMgMS4wNzQyNiwtMC4wMDA3OSAxLjYxMTM5LC0wLjAwMTRjMS4xMjM3NiwtMC4wMDA3MSAyLjI0NzUyLDAuMDAwMzIgMy4zNzEyOCwwLjAwMjU3YzEuNDM3NTQsMC4wMDI3NCAyLjg3NTAyLDAuMDAxMTYgNC4zMTI1NSwtMC4wMDE3MmMxLjEwODU2LC0wLjAwMTc0IDIuMjE3MTIsLTAuMDAxMTkgMy4zMjU2OCwwLjAwMDA2YzAuNTI5OTQsMC4wMDAzMiAxLjA1OTg3LC0wLjAwMDA3IDEuNTg5ODEsLTAuMDAxMTljMC43NDE2OSwtMC4wMDEyMyAxLjQ4MzMxLDAuMDAwNjUgMi4yMjQ5OSwwLjAwMzMyYzAuMjE3MTUsLTAuMDAwOTggMC40MzQzLC0wLjAwMTk0IDAuNjU4MDMsLTAuMDAyOTVjMi4wNzQ5OCwwLjAxMzc4IDMuNjU2ODYsMC4yOTc2OCA1LjE5NzgsMS43NjljMS4wNTExOCwxLjE4NDEgMS4yNTYwMywyLjQwNTA1IDEuMTk1NjgsMy45MzQ1N2MtMC4yMDIyNywxLjg4NjkxIC0wLjc3MTExLDIuOTM5MTkgLTIuMjQ0ODQsNC4xNDQ5N2MtMC43NTQ3NSwwLjUxMTI4IC0xLjM4NzgzLDAuNTg2OTIgLTIuMjc0MjksMC41OTMwNWMtMC4yMjI3OCwwLjAwMjA3IC0wLjQ0NTU4LDAuMDA0MTMgLTAuNjc1MTEsMC4wMDYyNmMtMC4zNjU5MywwLjAwMTUzIC0wLjM2NTkzLDAuMDAxNTQgLTAuNzM5MjYsMC4wMDMxMWMtMC4yNTczNCwwLjAwMTk3IC0wLjUxNDY4LDAuMDAzOTMgLTAuNzc5ODEsMC4wMDU5NmMtMC44NTMzNCwwLjAwNTk4IC0xLjcwNjY3LDAuMDA5OTUgLTIuNTYwMDMsMC4wMTM0MWMtMC4yOTE0LDAuMDAxMjggLTAuNTgyOCwwLjAwMjU2IC0wLjg4MzAzLDAuMDAzODhjLTEuNTQyNTcsMC4wMDY0MyAtMy4wODUxMiwwLjAxMTA5IC00LjYyNzY5LDAuMDE0NTZjLTEuNTkyNiwwLjAwNCAtMy4xODUwNywwLjAxNDc3IC00Ljc3NzYzLDAuMDI3MDJjLTEuMjI1MSwwLjAwODA5IC0yLjQ1MDE4LDAuMDEwODcgLTMuNjc1MywwLjAxMjIzYy0wLjU4Njk5LDAuMDAxNjEgLTEuMTczOTgsMC4wMDUyNyAtMS43NjA5NSwwLjAxMTAzYy0wLjgyMjUxLDAuMDA3NjEgLTEuNjQ0NywwLjAwNzYxIC0yLjQ2NzIzLDAuMDA1ODNjLTAuMjQxNTMsMC4wMDM5NCAtMC40ODMwNSwwLjAwNzg5IC0wLjczMTg5LDAuMDExOTZjLTEuNTg2NjgsLTAuMDE0MDMgLTIuNjE2MzksLTAuMzQwNDEgLTMuODQ4NzIsLTEuMzU0NTFjLTEuMTgyOTEsLTEuMjE0MDMgLTEuNDcwNjcsLTIuMzk4MiAtMS41NDc5LC00LjA1NzYxYzAuMDMwNzgsLTEuNjU2MjQgMC41NTI1OCwtMi41NjQ5NSAxLjY0MDg5LC0zLjc2MzYzYzEuNTA3ODYsLTEuNDI1MjMgMy41MDMyMiwtMS4zODY4NiA1LjQ1MDA4LC0xLjM3ODEzeiIgZmlsbD0iI2ZlYTczMSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTMwOC43MDk3NSwyMTguOTc5MTFjMS4xOTU4MSwxLjAzMjYgMS44MzMwNywyLjYzMTY5IDEuOTY4Nyw0LjE3Nzg1Yy0wLjAzMDE3LDEuNDkyMzEgLTAuNDkxNDMsMi44NjQ1MiAtMS40OTUzMSwzLjk4MTUzYy0xLjc1ODczLDEuNTc4MjYgLTMuMTc2NjUsMS44MjQ3OCAtNS40OTkzOSwxLjc1OTI0Yy0xLjM0NzYyLC0wLjA5NTA5IC0yLjI1NjEzLC0wLjU2MDE3IC0zLjE3OTQsLTEuNTQ3OWMtMS4zNTM5OSwtMS43NDUwNyAtMS42NzIzOSwtMy4zMzc3MyAtMS40NDI3MSwtNS41MzAzOGMwLjQ2NjQ1LC0xLjU2MjgzIDEuMjU5OTUsLTIuNjc5MjkgMi42MjE0OSwtMy41Nzc2NWMyLjQyMDYzLC0xLjI5MzcgNC44NDk4MSwtMC43ODY0NiA3LjAyNjYzLDAuNzM3MzJ6IiBmaWxsPSIjZmRhNzMxIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMzA3LjYxMjY5LDE5OC44NzEzN2MxLjIwMzEzLDAuNzM2NTYgMi4yNDYyLDEuOTA4NDcgMi43NTAxNiwzLjIzMTA3YzAuMTg4NDIsMS44MzI2NCAwLjM3NTQxLDMuODU1OTEgLTAuODA5NjQsNS4zODI5MmMtMS42NTkxMywxLjYzOTI5IC0yLjkxMzgyLDIuMTQyMjMgLTUuMjU2OTQsMi4xNDcyN2MtMS41MjkyLC0wLjAyOTg5IC0yLjU4NDExLC0wLjMyMDQ3IC0zLjY3NTQ1LC0xLjM5Nzc0Yy0xLjM0NzYzLC0xLjU1Mjg3IC0xLjYzNzY4LC0yLjc5MDY1IC0xLjYxMDg0LC00Ljc5NDk0YzAuMTA2NTEsLTEuMjcwMzYgMC40OTcyMiwtMi4yMDA5MyAxLjI5OSwtMy4xODU5OGMwLjIyMzE3LC0wLjE4MzQ5IDAuNDQ2MzQsLTAuMzY2OTkgMC42NzYyNywtMC41NTYwNWMwLjEyNDkxLC0wLjExMjIgMC4yNDk4MiwtMC4yMjQ0MSAwLjM3ODUyLC0wLjM0MDAxYzEuNjk0ODUsLTEuMzE2MTcgNC4zMTY3OCwtMS4zNDI3OCA2LjI0ODkyLC0wLjQ4NjU0eiIgZmlsbD0iI2ZlYTczMSIgc3Ryb2tlLXdpZHRoPSIxIi8+PC9nPjwvZz48L3N2Zz4="; - - class FirebaseDB { - constructor() { - this.api = "https://guessthepin-2fe64-default-rtdb.europe-west1.firebasedatabase.app"; - } - - getInfo() { - return { - id: "FirebaseDB", - name: "Firebase DB", - color1: "#fea631", - menuIconURI: icon, - blocks: [ - {blockType: Scratch.BlockType.LABEL, text: "Made by @logise on Discord"}, - { - opcode: "setKey", - blockType: Scratch.BlockType.COMMAND, - text: "set key [KEY] to value [VALUE]", - arguments: { - KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" }, - VALUE: { type: Scratch.ArgumentType.STRING, defaultValue: "value" } - } - }, - { - opcode: "getKey", - blockType: Scratch.BlockType.REPORTER, - text: "get key [KEY]", - arguments: { - KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" } - } - }, - {blockType: Scratch.BlockType.LABEL, text: "Password Blocks:"}, - { - opcode: "setKeyWithPassword", - blockType: Scratch.BlockType.COMMAND, - text: "set key [KEY] to value [VALUE] with password [PASSWORD]", - arguments: { - KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" }, - VALUE: { type: Scratch.ArgumentType.STRING, defaultValue: "value" }, - PASSWORD: { type: Scratch.ArgumentType.STRING, defaultValue: "password" } - } - }, - { - opcode: "getKeyWithPassword", - blockType: Scratch.BlockType.REPORTER, - text: "get key [KEY] with password [PASSWORD]", - arguments: { - KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" }, - PASSWORD: { type: Scratch.ArgumentType.STRING, defaultValue: "password" } - } - }, - { - opcode: "checkPassword", - blockType: Scratch.BlockType.BOOLEAN, - text: "check if password [PASSWORD] is valid for key [KEY]", - arguments: { - PASSWORD: { type: Scratch.ArgumentType.STRING, defaultValue: "password" }, - KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" } - } - } - ] - }; - } - - async delay() { - const d = Math.random() * 500; - return new Promise(r => setTimeout(r, d)); - } - - async setKey(args) { - await this.delay(); - const { KEY, VALUE } = args; - if (VALUE.length > 8000) return; - await fetch(`${this.api}/pin/${encodeURIComponent(KEY)}.json`, { - method: "PUT", - body: JSON.stringify(VALUE) - }); - } - - async getKey(args) { - await this.delay(); - const { KEY } = args; - const res = await fetch(`${this.api}/pin/${encodeURIComponent(KEY)}.json`); - const data = await res.json(); - return data ?? ""; - } - - async deriveKey(password, salt) { - const enc = new TextEncoder(); - const keyMaterial = await crypto.subtle.importKey( - "raw", enc.encode(password), "PBKDF2", false, ["deriveKey"] - ); - return await crypto.subtle.deriveKey( - { - name: "PBKDF2", - salt, - iterations: 100000, - hash: "SHA-256" - }, - keyMaterial, - { name: "AES-GCM", length: 256 }, - false, - ["encrypt", "decrypt"] - ); - } - - async setKeyWithPassword(args) { - await this.delay(); - const { KEY, VALUE, PASSWORD } = args; - if (VALUE.length > 8000) return; - - const enc = new TextEncoder(); - const iv = crypto.getRandomValues(new Uint8Array(12)); - const salt = crypto.getRandomValues(new Uint8Array(16)); - const key = await this.deriveKey(PASSWORD, salt); - const encrypted = await crypto.subtle.encrypt( - { name: "AES-GCM", iv }, key, enc.encode(VALUE) - ); - - const fullPackage = { - iv: Array.from(iv), - salt: Array.from(salt), - data: Array.from(new Uint8Array(encrypted)) - }; - - await fetch(`${this.api}/cypher/${encodeURIComponent(KEY)}.json`, { - method: "PUT", - body: JSON.stringify(fullPackage) - }); - } - - async getKeyWithPassword(args) { - await this.delay(); - const { KEY, PASSWORD } = args; - - const res = await fetch(`${this.api}/cypher/${encodeURIComponent(KEY)}.json`); - const encryptedPackage = await res.json(); - if (!encryptedPackage || !encryptedPackage.data || !encryptedPackage.iv || !encryptedPackage.salt) return ""; - - try { - const iv = new Uint8Array(encryptedPackage.iv); - const salt = new Uint8Array(encryptedPackage.salt); - const data = new Uint8Array(encryptedPackage.data); - const key = await this.deriveKey(PASSWORD, salt); - const decrypted = await crypto.subtle.decrypt( - { name: "AES-GCM", iv }, key, data - ); - return new TextDecoder().decode(decrypted); - } catch (e) { - return ""; - } - } - - async checkPassword(args) { - await this.delay(); - const { KEY, PASSWORD } = args; - - const res = await fetch(`${this.api}/cypher/${encodeURIComponent(KEY)}.json`); - const encryptedPackage = await res.json(); - if (!encryptedPackage || !encryptedPackage.data || !encryptedPackage.iv || !encryptedPackage.salt) return false; - - try { - const iv = new Uint8Array(encryptedPackage.iv); - const salt = new Uint8Array(encryptedPackage.salt); - const data = new Uint8Array(encryptedPackage.data); - const key = await this.deriveKey(PASSWORD, salt); - await crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, data); - return true; - } catch (e) { - return false; - } - } +(function (Scratch) { + "use strict"; + if (!Scratch.extensions.unsandboxed) + throw new Error("FirebaseDB must run unsandboxed"); + const icon = + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIyMDguMDY5MzUiIGhlaWdodD0iMjA4LjA2OTM1IiB2aWV3Qm94PSIwLDAsMjA4LjA2OTM1LDIwOC4wNjkzNSI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTIxNS45NjUzMiwtNzUuOTY1MzMpIj48ZyBzdHJva2U9Im5vbmUiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTIxNS45NjUzMywxODBjMCwtNTcuNDU2NzYgNDYuNTc3OTEsLTEwNC4wMzQ2NyAxMDQuMDM0NjgsLTEwNC4wMzQ2N2M1Ny40NTY3NywwIDEwNC4wMzQ2OCw0Ni41Nzc5MSAxMDQuMDM0NjgsMTA0LjAzNDY4YzAsNTcuNDU2NzYgLTQ2LjU3NzkxLDEwNC4wMzQ2OCAtMTA0LjAzNDY3LDEwNC4wMzQ2OGMtNTcuNDU2NzcsMCAtMTA0LjAzNDY3LC00Ni41Nzc5MSAtMTA0LjAzNDY3LC0xMDQuMDM0Njd6IiBmaWxsPSIjZmVhNjMxIiBzdHJva2Utd2lkdGg9IjAiLz48cGF0aCBkPSJNMjc1LjE0NjI0LDE4Ni4yMDEwNGMwLjE3ODQ3LC0wLjAwMDUgMC4zNTY5NCwtMC4wMDA5OCAwLjU0MDgyLC0wLjAwMTQ5YzAuNTk4NDYsLTAuMDAxMzYgMS4xOTY5MiwtMC4wMDEwMSAxLjc5NTM4LC0wLjAwMDY3YzAuNDMzMjYsLTAuMDAwNjIgMC44NjY1MiwtMC4wMDEzNCAxLjI5OTc4LC0wLjAwMjE2YzEuMTkxMDMsLTAuMDAxOTQgMi4zODIwNSwtMC4wMDIzNyAzLjU3MzA4LC0wLjAwMjU1YzEuMjg0NDIsLTAuMDAwNDUgMi41Njg4NSwtMC4wMDIyNiAzLjg1MzI4LC0wLjAwMzg4YzIuODA4OTYsLTAuMDAzMjYgNS42MTc5MiwtMC4wMDQ3MSA4LjQyNjg4LC0wLjAwNTc3YzEuNzU0MywtMC4wMDA2NiAzLjUwODYsLTAuMDAxNjkgNS4yNjI5LC0wLjAwMjc3YzQuODU4MDcsLTAuMDAyOTMgOS43MTYxNCwtMC4wMDU0MSAxNC41NzQyMSwtMC4wMDYyMmMwLjMxMDkyLC0wLjAwMDA2IDAuNjIxODUsLTAuMDAwMSAwLjk0MjE5LC0wLjAwMDE2YzAuMzExNjcsLTAuMDAwMDYgMC42MjMzMywtMC4wMDAxIDAuOTQ0NDQsLTAuMDAwMTZjMC42MzE1NCwtMC4wMDAxIDEuMjYzMDgsLTAuMDAwMjEgMS44OTQ2MiwtMC4wMDAzMmMwLjMxMzI3LC0wLjAwMDA2IDAuNjI2NTMsLTAuMDAwMSAwLjk0OTI5LC0wLjAwMDE2YzUuMDc0MzQsLTAuMDAwOTUgMTAuMTQ4NjYsLTAuMDA1MTUgMTUuMjIzLC0wLjAxMDc1YzUuMjEwOTgsLTAuMDA1NzEgMTAuNDIxOTQsLTAuMDA4NjkgMTUuNjMyOTMsLTAuMDA4OTdjMi45MjUyNSwtMC4wMDAyMiA1Ljg1MDUsLTAuMDAxNiA4Ljc3NTc2LC0wLjAwNTk3YzIuNDkxMzMsLTAuMDAzNyA0Ljk4MjY0LC0wLjAwNDkzIDcuNDczOTcsLTAuMDAyOTVjMS4yNzA0NywwLjAwMDk0IDIuNTQwOTMsMC4wMDA3MiAzLjgxMTQsLTAuMDAyNjZjMS4xNjQ2OSwtMC4wMDMwNyAyLjMyOTMxLC0wLjAwMjc3IDMuNDk0LDAuMDAwMTRjMC40MTk3NSwwLjAwMDQ3IDAuODM5NSwtMC4wMDAyNiAxLjI1OTI1LC0wLjAwMjM2YzQuNjU3MjYsLTAuMDIxODUgOC44OTI1NiwwLjY5Mzc4IDEyLjM4ODc4LDQuMDY5MjNjMi4yOTkzNiwyLjU4MjY3IDMuMDM5OTUsNC45ODc0MyAzLjAyNzY2LDguMzc0MThjMC4wMDEzNywwLjMyMjEzIDAuMDAzMDUsMC42NDQyNSAwLjAwNSwwLjk2NjM4YzAuMDA0MywwLjg3MDQ4IDAuMDA0MDMsMS43NDA5IDAuMDAyNjYsMi42MTEzOWMtMC4wMDA3NCwwLjcyOTQ4IDAuMDAwNzIsMS40NTg5NCAwLjAwMjE3LDIuMTg4NDFjMC4wMDMzNywxLjcyMzE1IDAuMDAzMDEsMy40NDYyOCAwLjAwMDI3LDUuMTY5NDNjLTAuMDAyNzUsMS43NzA0MyAwLjAwMDYxLDMuNTQwNzcgMC4wMDcwNyw1LjMxMTE5YzAuMDA1MzUsMS41MjU5IDAuMDA2OTEsMy4wNTE3NyAwLjAwNTUxLDQuNTc3NjljLTAuMDAwODEsMC45MDg3MiAtMC4wMDAyNiwxLjgxNzM3IDAuMDAzOTEsMi43MjYwOGMwLjAwMzc2LDAuODU2MDIgMC4wMDI3MiwxLjcxMTkxIC0wLjAwMTc2LDIuNTY3OTFjLTAuMDAxMjksMC40NTg1NiAwLjAwMjEsMC45MTcxMyAwLjAwNTcsMS4zNzU2N2MtMC4wMzE3MiwzLjc2NTQxIC0xLjMwNDM4LDcuMTM1MDYgLTMuODk4ODIsOS44NjYyOGMtMy4zMzE5MSwzLjI0MjAxIC03LjA3ODEsMy43NDA2NiAtMTEuNTMxMzYsMy43MzM3NGMtMC40MzQ1MywwLjAwMTA3IC0wLjg2OTA3LDAuMDAyMzUgLTEuMzAzNiwwLjAwMzgyYy0xLjE5MTIxLDAuMDAzNCAtMi4zODI0MSwwLjAwMzggLTMuNTczNjMsMC4wMDM3Yy0xLjI4NTksMC4wMDAzOSAtMi41NzE4LDAuMDAzNTQgLTMuODU3NjksMC4wMDYzYy0yLjgxMDQ0LDAuMDA1NDkgLTUuNjIwODgsMC4wMDc0IC04LjQzMTMyLDAuMDA4NjFjLTEuNzU1OCwwLjAwMDc5IC0zLjUxMTU5LDAuMDAyMzUgLTUuMjY3MzksMC4wMDQwOWMtNC44NjQwOCwwLjAwNDcxIC05LjcyODE2LDAuMDA4NjUgLTE0LjU5MjI1LDAuMDA5MzRjLTAuNDY2NywwLjAwMDA3IC0wLjQ2NjY5LDAuMDAwMDcgLTAuOTQyODEsMC4wMDAxNGMtMC42MzA3LDAuMDAwMDkgLTEuMjYxNCwwLjAwMDE4IC0xLjg5MjEsMC4wMDAyN2MtMC40Njk2LDAuMDAwMDcgLTAuNDY5NiwwLjAwMDA3IC0wLjk0ODY5LDAuMDAwMTRjLTAuNDcwMTcsMC4wMDAwNyAtMC40NzAxOCwwLjAwMDA3IC0wLjk0OTg1LDAuMDAwMTNjLTUuMDc3ODYsMC4wMDA4NSAtMTAuMTU1NywwLjAwNzM1IC0xNS4yMzM1NSwwLjAxNjM0Yy01LjIxNjk4LDAuMDA5MTYgLTEwLjQzMzk0LDAuMDEzODEgLTE1LjY1MDkzLDAuMDEzODhjLTIuOTI3NjksMC4wMDAxNCAtNS44NTUzNCwwLjAwMjE3IC04Ljc4MzAzLDAuMDA5MTRjLTIuNDkzMTUsMC4wMDU5IC00Ljk4NjI3LDAuMDA3NjQgLTcuNDc5NDIsMC4wMDQwM2MtMS4yNzEwNSwtMC4wMDE3MiAtMi41NDIwMSwtMC4wMDE1MyAtMy44MTMwNSwwLjAwMzk0Yy0xLjE2NTc1LDAuMDA0OTggLTIuMzMxMzYsMC4wMDQzMSAtMy40OTcxLC0wLjAwMDY5Yy0wLjQxOTU4LC0wLjAwMDgzIC0wLjgzOTE3LDAuMDAwMzIgLTEuMjU4NzQsMC4wMDM3N2MtNC4xODkxNCwwLjAzMjI2IC03LjY3MzUxLC0wLjc2MzE1IC0xMC44MTgxMSwtMy43MzcxYy0yLjY5NDQzLC0yLjg1ODQ0IC0zLjQ3MzgsLTYuMjA4NjkgLTMuNDU5NzEsLTEwLjAyOThjLTAuMDAxNjUsLTAuMzE2NjcgLTAuMDAzMywtMC42MzMzNCAtMC4wMDUsLTAuOTU5NmMtMC4wMDQyOCwtMC44NjEgLTAuMDA0MDQsLTEuNzIxOTQgLTAuMDAyNjYsLTIuNTgyOTRjMC4wMDA3NSwtMC43MjIzNCAtMC4wMDA3MywtMS40NDQ2NyAtMC4wMDIxOCwtMi4xNjcwMWMtMC4wMDMzNiwtMS43MDU5OCAtMC4wMDMwMSwtMy40MTE5NCAtMC4wMDAyNiwtNS4xMTc5M2MwLjAwMjc2LC0xLjc1MiAtMC4wMDA2MywtMy41MDM5MiAtMC4wMDcwNywtNS4yNTU5MmMtMC4wMDUzNSwtMS41MTE2MiAtMC4wMDY5MiwtMy4wMjMyMiAtMC4wMDU1MiwtNC41MzQ4NWMwLjAwMDgxLC0wLjg5OTU2IDAuMDAwMjcsLTEuNzk5MDcgLTAuMDAzOSwtMi42OTg2M2MtMC4wMDM3NiwtMC44NDY3NSAtMC4wMDI3MywtMS42OTMzNyAwLjAwMTc2LC0yLjU0MDEyYzAuMDAxMjksLTAuNDUzMzkgLTAuMDAyMDksLTAuOTA2NzkgLTAuMDA1NywtMS4zNjAxNmMwLjAzMDMzLC0zLjU2MDggMS4yMTk2NSwtNi44NTEyMSAzLjczNDQ1LC05LjQyMzE2YzIuNTI0MjYsLTIuMDQ2OTQgNS4wNDYzOCwtMy4xNjU5MiA4LjMwNTA5LC0zLjE1NzQ3eiIgZmlsbD0iI2E0NGMxNSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTMwNi4wNzk4MSwxMTguMDE5NTljMC41NTM5OSwwLjQ0Njg1IDEuMDk4MTIsMC45MDM4OCAxLjYzODA3LDEuMzY3NTdjMC4xMzQyMSwwLjExNTA0IDAuMjY4NDMsMC4yMzAwNiAwLjQwNjcxLDAuMzQ4NThjNC4yODA5NiwzLjcxMzU1IDcuNjIxOTEsOC4zMDUwNCAxMC4xNzMxNiwxMy4zNTcxNWMwLDAuMTU4NyAwLDAuMzE3NCAwLDAuNDgwOWMwLjI2OTYxLC0wLjAwMDY2IDAuNTM5MjMsLTAuMDAxMzMgMC44MTcwMiwtMC4wMDIwMmM2LjU2MDI5LC0wLjAxNjAyIDEzLjEyMDU5LC0wLjAyNzg3IDE5LjY4MDksLTAuMDM1MzZjMy4xNzI1MSwtMC4wMDM3MiA2LjM0NTAyLC0wLjAwODc5IDkuNTE3NTMsLTAuMDE3MDRjMi43NjUxNSwtMC4wMDcxOSA1LjUzMDI5LC0wLjAxMTg0IDguMjk1NDUsLTAuMDEzNDVjMS40NjQxMywtMC4wMDA5NCAyLjkyODI1LC0wLjAwMzE1IDQuMzkyMzcsLTAuMDA4NGMxLjM3ODM1LC0wLjAwNDkgMi43NTY2NywtMC4wMDY0IDQuMTM1MDQsLTAuMDA1MzJjMC41MDU1OCwtMC4wMDAyIDEuMDExMTcsLTAuMDAxNjMgMS41MTY3NCwtMC4wMDQ0YzAuNjkxMTYsLTAuMDAzNTkgMS4zODIxOCwtMC4wMDI3MiAyLjA3MzM1LC0wLjAwMDc1YzAuMTk5MjksLTAuMDAyMSAwLjM5ODU4LC0wLjAwNDIxIDAuNjAzOTEsLTAuMDA2MzdjMy42MDI5NCwwLjAyNzY0IDUuODI4MzUsMi41NzExOSA4LjI4ODc0LDQuODgzMzVjMC41OTUxNSwwLjU1ODY4IDEuMTk3MjMsMS4xMDY2MyAxLjgxMzcyLDEuNjQxODRjMC4xNDM4MiwwLjEyNTUzIDAuMjg3NjQsMC4yNTEwNiAwLjQzNTgyLDAuMzgwNGMwLjM1Nzk0LDAuMzA4MTUgMC43MTkyOCwwLjYxMjM3IDEuMDgyMDMsMC45MTQ4NWMxLjQzNDg3LDEuMjI4NCAyLjUyNzU2LDIuMjQyNTkgMi44NDY5LDQuMTUyNDhjMC4xMDAyMSwxLjU4Mzg3IC0wLjMzMTY2LDIuNzQyOTQgLTEuMjk5LDMuOTg5OTljLTAuNDYzOSwwLjQ1NjI4IC0wLjk0NDA3LDAuODY5NDQgLTEuNDQ5MjksMS4yNzkyOGMtMC40NTU0NywwLjM4NzgyIC0wLjgxODM1LDAuNzgyOCAtMS4xOTU2OCwxLjI0NTQ2Yy0wLjYyMjA3LDAuNzUyNzggLTEuMzA0MDksMS4zNTkxNyAtMi4wNDg1NCwxLjk4ODQyYy0wLjk2MjIyLDAuODY1MjQgLTEuODU4NjYsMS43OTczNCAtMi43NTc2NywyLjcyNzY4Yy0xLjY2NzU3LDEuNzAxIC0zLjE2MTgyLDIuMjY1MzUgLTUuNTE4MTgsMi40NTIzNmMtMy42MDM4NywtMC4xNDI0NSAtNS44MjA2NSwtMi42OTA4MSAtOC4xODAwNCwtNS4xMzAyNmMtMC4xNjIxMSwtMC4xNTY4NCAtMC4zMjQyMiwtMC4zMTM2OCAtMC40OTEyNCwtMC40NzUyN2MtMC4xNDM4MiwtMC4xNDM4MiAtMC4yODc2NCwtMC4yODc2NCAtMC40MzU4MiwtMC40MzU4MmMtMC44MDAwNSwtMC40MzQzMSAtMS4zMzgwMywtMC4yNDYyNSAtMi4yMDkxNSwtMC4wNDUwOWMtMC42MzQ4NiwwLjQ0NTkyIC0wLjYzNDg2LDAuNDQ1OTMgLTEuMTc0MDgsMS4wNTAxYy0wLjIwNjEyLDAuMjEyOTQgLTAuNDEyMjQsMC40MjU4NyAtMC42MjQ2MSwwLjY0NTI3Yy0wLjIwOTg0LDAuMjI0MSAtMC40MTk2OCwwLjQ0ODIgLTAuNjM1ODgsMC42NzkwOWMtMC40MjAzMiwwLjQ0MTI1IC0wLjg0MTcsMC44ODE0OSAtMS4yNjQyNSwxLjMyMDYxYy0wLjE4NDQ2LDAuMTk2MTcgLTAuMzY4OTIsMC4zOTIzMiAtMC41NTg5OCwwLjU5NDQ0Yy0xLjU3MjA0LDEuNDgxNjQgLTMuMjMzNjIsMS44MzAxNCAtNS4zMzk2LDEuNzc4MTRjLTMuMTA1ODgsLTAuMjM1ODkgLTQuNzQxMzcsLTEuOTgzOTMgLTYuNjk5ODgsLTQuMjQ5NGMtMC4zNjg0MiwtMC40MzIzMyAtMC43MzI2MiwtMC44Njc4OSAtMS4wOTYsLTEuMzA0NDZjLTAuNTA3NzksLTAuNjAzNDEgLTEuMDA5MTUsLTEuMTkzNTggLTEuNjAyMzgsLTEuNzE2MDNjLTAuNjA2OTcsLTAuMDU1MzEgLTAuNjA2OTgsLTAuMDU1MzEgLTEuMjAyMjYsMC4yNDA0NWMtMC40MTA2NCwwLjM5MzY4IC0wLjgwNjYxLDAuNzkzOTUgLTEuMjAyMjUsMS4yMDIyNmMtMC4yOTg3NiwwLjI5NzA1IC0wLjU5ODEyLDAuNTkzNSAtMC44OTc5NCwwLjg4OTQ4Yy0wLjMyMTg3LDAuMzE5NjUgLTAuNjQzNzIsMC42MzkzMiAtMC45NjU1NiwwLjk1ODk5Yy0wLjE2NDU4LDAuMTYyNTggLTAuMzI5MTcsMC4zMjUxNCAtMC40OTg3NCwwLjQ5MjY0Yy0wLjE1NjUzLDAuMTU1NzUgLTAuMzEzMDYsMC4zMTE1IC0wLjQ3NDMzLDAuNDcxOThjLTAuMTQyMTksMC4xNDA5NCAtMC4yODQzOSwwLjI4MTg3IC0wLjQzMDg5LDAuNDI3MDhjLTAuMzYyOTUsMC4zNTc5IC0wLjE3Mzg3LDAuMTg3MiAtMS4zMDExMSwxLjU2ODg2Yy0xLjU1NzYzLDAuOTMzODMgLTMuMTc3NDMsMS4xMDU5MyAtNC45NTM2NywxLjEwODMzYy0wLjIzMTQzLDAuMDAzOTcgLTAuNDYyODYsMC4wMDc5NSAtMC43MDEzLDAuMDEyMDVjLTAuNzI5OTQsMC4wMTE1NiAtMS40NTk3NSwwLjAxNjc4IC0yLjE4OTc1LDAuMDIxNzdjLTAuNDk4NzYsMC4wMDY3OCAtMC45OTc1MSwwLjAxMzk4IC0xLjQ5NjI1LDAuMDIxNmMtMS4yMTQ0NSwwLjAxNzY3IC0yLjQyODg1LDAuMDI5NjUgLTMuNjQzNCwwLjAzODUxYy0wLjA3NzM0LDAuMTUyNDIgLTAuMTU0NjcsMC4zMDQ4NCAtMC4yMzQzNSwwLjQ2MTg4Yy0xLjk1MjU0LDMuODM0MDUgLTMuOTIwMDgsNy4zMjQ1NCAtNi43Mzg3NCwxMC41OTg4OGMtMC4xOTA5NCwwLjIyMzQ4IC0wLjM4MTg3LDAuNDQ2OTYgLTAuNTc4NTksMC42NzcyMWMtNi40Njg5Niw3LjM1OTQ3IC0xNS40MjU2OCwxMS4wNjQ4OCAtMjUuMDQxMTEsMTEuNzg4NThjLTkuMjI4ODYsMC41OTAwMSAtMTguNjIyMjMsLTEuOTY3MzggLTI1LjYzNDk1LC04LjA3Mjg1Yy0wLjcyNzAzLC0wLjY0NDY0IC0xLjQyODY3LC0xLjMxMTI4IC0yLjEyNTU2LC0xLjk4ODQyYy0wLjE3OTE1LC0wLjE3Mjk2IC0wLjM1ODMxLC0wLjM0NTkxIC0wLjU0Mjg5LC0wLjUyNDFjLTYuMzUyNCwtNi41ODY4IC05Ljg0MjA4LC0xNS40ODQwNSAtOS44NDEwNywtMjQuNTI5NTZjLTAuMDAwNTMsLTAuNTIxNzMgLTAuMDA0OTEsLTEuMDQzMzQgLTAuMDA5NDYsLTEuNTY1MDVjLTAuMDA4MTIsLTEuOTkxNCAwLjEzMjM1LC0zLjg4NjY0IDAuNTM0OTEsLTUuODQyMjJjMC4wMzI1NywtMC4xODA0NyAwLjA2NTEzLC0wLjM2MDk1IDAuMDk4NjgsLTAuNTQ2ODljMS4zMTQ0NCwtNy4yNzgxNiA0Ljk1Mzk1LC0xNC4xNDYxIDEwLjY2MzQsLTE4Ljk0NDdjMC41MjczMywtMC40NTU2NiAxLjAyODUxLC0wLjkzMzIyIDEuNTMxMDYsLTEuNDE1ODJjMTEuNzIzOTcsLTExLjEzNDI1IDMyLjIzNjE2LC0xMS4xNzI5OSA0NC43Mzg5MiwtMS4zNzk0MnoiIGZpbGw9IiNhNDRjMTUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yODEuODY5MzYsMTM4LjYwOTE4YzIuMzU5MTksMi4wMTg2NSA0LjE1NSw0LjU2NzIgNC41MDI4Myw3LjcyMTY5YzAuMTI3MDUsMy4xNTMwMyAtMC45ODc3MSw1Ljg0MDE2IC0yLjk4NDk4LDguMjA3MjhjLTIuMjAwMzUsMi4zNDIxOSAtNC43Mjg2NywzLjMwNzcxIC03Ljg5OTg1LDMuNDE3OThjLTEuOTMxNDksMC4wMjY5NCAtMy41NzgwOSwtMC4wNTU2NSAtNS4yNzk4OSwtMS4wNTg1NWMtMC4xODA3LC0wLjA5OTE5IC0wLjM2MTQxLC0wLjE5ODM3IC0wLjU0NzU5LC0wLjMwMDU3Yy0yLjcyMDU5LC0xLjYzNyAtNC4xNzE5NCwtMy45MTU4MiAtNS4xMjgzOCwtNi44ODM4NmMtMC42MjQwOCwtMy4zNTUyMSAwLjE5NzM4LC02LjIyOCAyLjA3NDg0LC05LjAyODJjMS42NjIyMSwtMi4xNjQ4MiAzLjk0NTUsLTMuNjY1MzUgNi42NDYyMiwtNC4xNTgxMmMzLjA0NDg5LC0wLjM2NjYxIDYuMTYwNiwwLjE3NDk1IDguNjE2OCwyLjA4MjM1eiIgZmlsbD0iI2ZlYTYzMSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTMzMC44MTM5LDIwNy44MTEwNGMwLjIzNDA2LC0wLjAwMDg0IDAuNDY4MTIsLTAuMDAxNjggMC43MDkyOCwtMC4wMDI1NWMwLjc2ODc2LC0wLjAwMjExIDEuNTM3NDcsLTAuMDAwNzIgMi4zMDYyMywwLjAwMDkxYzAuNTM3MTMsLTAuMDAwMzMgMS4wNzQyNiwtMC4wMDA3OSAxLjYxMTM5LC0wLjAwMTRjMS4xMjM3NiwtMC4wMDA3MSAyLjI0NzUyLDAuMDAwMzIgMy4zNzEyOCwwLjAwMjU3YzEuNDM3NTQsMC4wMDI3NCAyLjg3NTAyLDAuMDAxMTYgNC4zMTI1NSwtMC4wMDE3MmMxLjEwODU2LC0wLjAwMTc0IDIuMjE3MTIsLTAuMDAxMTkgMy4zMjU2OCwwLjAwMDA2YzAuNTI5OTQsMC4wMDAzMiAxLjA1OTg3LC0wLjAwMDA3IDEuNTg5ODEsLTAuMDAxMTljMC43NDE2OSwtMC4wMDEyMyAxLjQ4MzMxLDAuMDAwNjUgMi4yMjQ5OSwwLjAwMzMyYzAuMjE3MTUsLTAuMDAwOTggMC40MzQzLC0wLjAwMTk0IDAuNjU4MDMsLTAuMDAyOTVjMi4wNzQ5OCwwLjAxMzc4IDMuNjU2ODYsMC4yOTc2OCA1LjE5NzgsMS43NjljMS4wNTExOCwxLjE4NDEgMS4yNTYwMywyLjQwNTA1IDEuMTk1NjgsMy45MzQ1N2MtMC4yMDIyNywxLjg4NjkxIC0wLjc3MTExLDIuOTM5MTkgLTIuMjQ0ODQsNC4xNDQ5N2MtMC43NTQ3NSwwLjUxMTI4IC0xLjM4NzgzLDAuNTg2OTIgLTIuMjc0MjksMC41OTMwNWMtMC4yMjI3OCwwLjAwMjA3IC0wLjQ0NTU4LDAuMDA0MTMgLTAuNjc1MTEsMC4wMDYyNmMtMC4zNjU5MywwLjAwMTUzIC0wLjM2NTkzLDAuMDAxNTQgLTAuNzM5MjYsMC4wMDMxMWMtMC4yNTczNCwwLjAwMTk3IC0wLjUxNDY4LDAuMDAzOTMgLTAuNzc5ODEsMC4wMDU5NmMtMC44NTMzNCwwLjAwNTk4IC0xLjcwNjY3LDAuMDA5OTUgLTIuNTYwMDMsMC4wMTM0MWMtMC4yOTE0LDAuMDAxMjggLTAuNTgyOCwwLjAwMjU2IC0wLjg4MzAzLDAuMDAzODhjLTEuNTQyNTcsMC4wMDY0MyAtMy4wODUxMiwwLjAxMTA5IC00LjYyNzY5LDAuMDE0NTZjLTEuNTkyNiwwLjAwNCAtMy4xODUwNywwLjAxNDc3IC00Ljc3NzYzLDAuMDI3MDJjLTEuMjI1MSwwLjAwODA5IC0yLjQ1MDE4LDAuMDEwODcgLTMuNjc1MywwLjAxMjIzYy0wLjU4Njk5LDAuMDAxNjEgLTEuMTczOTgsMC4wMDUyNyAtMS43NjA5NSwwLjAxMTAzYy0wLjgyMjUxLDAuMDA3NjEgLTEuNjQ0NywwLjAwNzYxIC0yLjQ2NzIzLDAuMDA1ODNjLTAuMjQxNTMsMC4wMDM5NCAtMC40ODMwNSwwLjAwNzg5IC0wLjczMTg5LDAuMDExOTZjLTEuNTg2NjgsLTAuMDE0MDMgLTIuNjE2MzksLTAuMzQwNDEgLTMuODQ4NzIsLTEuMzU0NTFjLTEuMTgyOTEsLTEuMjE0MDMgLTEuNDcwNjcsLTIuMzk4MiAtMS41NDc5LC00LjA1NzYxYzAuMDMwNzgsLTEuNjU2MjQgMC41NTI1OCwtMi41NjQ5NSAxLjY0MDg5LC0zLjc2MzYzYzEuNTA3ODYsLTEuNDI1MjMgMy41MDMyMiwtMS4zODY4NiA1LjQ1MDA4LC0xLjM3ODEzeiIgZmlsbD0iI2ZlYTczMSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTMwOC43MDk3NSwyMTguOTc5MTFjMS4xOTU4MSwxLjAzMjYgMS44MzMwNywyLjYzMTY5IDEuOTY4Nyw0LjE3Nzg1Yy0wLjAzMDE3LDEuNDkyMzEgLTAuNDkxNDMsMi44NjQ1MiAtMS40OTUzMSwzLjk4MTUzYy0xLjc1ODczLDEuNTc4MjYgLTMuMTc2NjUsMS44MjQ3OCAtNS40OTkzOSwxLjc1OTI0Yy0xLjM0NzYyLC0wLjA5NTA5IC0yLjI1NjEzLC0wLjU2MDE3IC0zLjE3OTQsLTEuNTQ3OWMtMS4zNTM5OSwtMS43NDUwNyAtMS42NzIzOSwtMy4zMzc3MyAtMS40NDI3MSwtNS41MzAzOGMwLjQ2NjQ1LC0xLjU2MjgzIDEuMjU5OTUsLTIuNjc5MjkgMi42MjE0OSwtMy41Nzc2NWMyLjQyMDYzLC0xLjI5MzcgNC44NDk4MSwtMC43ODY0NiA3LjAyNjYzLDAuNzM3MzJ6IiBmaWxsPSIjZmRhNzMxIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMzA3LjYxMjY5LDE5OC44NzEzN2MxLjIwMzEzLDAuNzM2NTYgMi4yNDYyLDEuOTA4NDcgMi43NTAxNiwzLjIzMTA3YzAuMTg4NDIsMS44MzI2NCAwLjM3NTQxLDMuODU1OTEgLTAuODA5NjQsNS4zODI5MmMtMS42NTkxMywxLjYzOTI5IC0yLjkxMzgyLDIuMTQyMjMgLTUuMjU2OTQsMi4xNDcyN2MtMS41MjkyLC0wLjAyOTg5IC0yLjU4NDExLC0wLjMyMDQ3IC0zLjY3NTQ1LC0xLjM5Nzc0Yy0xLjM0NzYzLC0xLjU1Mjg3IC0xLjYzNzY4LC0yLjc5MDY1IC0xLjYxMDg0LC00Ljc5NDk0YzAuMTA2NTEsLTEuMjcwMzYgMC40OTcyMiwtMi4yMDA5MyAxLjI5OSwtMy4xODU5OGMwLjIyMzE3LC0wLjE4MzQ5IDAuNDQ2MzQsLTAuMzY2OTkgMC42NzYyNywtMC41NTYwNWMwLjEyNDkxLC0wLjExMjIgMC4yNDk4MiwtMC4yMjQ0MSAwLjM3ODUyLC0wLjM0MDAxYzEuNjk0ODUsLTEuMzE2MTcgNC4zMTY3OCwtMS4zNDI3OCA2LjI0ODkyLC0wLjQ4NjU0eiIgZmlsbD0iI2ZlYTczMSIgc3Ryb2tlLXdpZHRoPSIxIi8+PC9nPjwvZz48L3N2Zz4="; + + class FirebaseDB { + constructor() { + this.api = + "https://guessthepin-2fe64-default-rtdb.europe-west1.firebasedatabase.app"; } - Scratch.extensions.register(new FirebaseDB()); + getInfo() { + return { + id: "FirebaseDB", + name: "Firebase DB", + color1: "#fea631", + menuIconURI: icon, + blocks: [ + { + blockType: Scratch.BlockType.LABEL, + text: "Made by @logise on Discord", + }, + { + opcode: "setKey", + blockType: Scratch.BlockType.COMMAND, + text: "set key [KEY] to value [VALUE]", + arguments: { + KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" }, + VALUE: { + type: Scratch.ArgumentType.STRING, + defaultValue: "value", + }, + }, + }, + { + opcode: "getKey", + blockType: Scratch.BlockType.REPORTER, + text: "get key [KEY]", + arguments: { + KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" }, + }, + }, + { blockType: Scratch.BlockType.LABEL, text: "Password Blocks:" }, + { + opcode: "setKeyWithPassword", + blockType: Scratch.BlockType.COMMAND, + text: "set key [KEY] to value [VALUE] with password [PASSWORD]", + arguments: { + KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" }, + VALUE: { + type: Scratch.ArgumentType.STRING, + defaultValue: "value", + }, + PASSWORD: { + type: Scratch.ArgumentType.STRING, + defaultValue: "password", + }, + }, + }, + { + opcode: "getKeyWithPassword", + blockType: Scratch.BlockType.REPORTER, + text: "get key [KEY] with password [PASSWORD]", + arguments: { + KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" }, + PASSWORD: { + type: Scratch.ArgumentType.STRING, + defaultValue: "password", + }, + }, + }, + { + opcode: "checkPassword", + blockType: Scratch.BlockType.BOOLEAN, + text: "check if password [PASSWORD] is valid for key [KEY]", + arguments: { + PASSWORD: { + type: Scratch.ArgumentType.STRING, + defaultValue: "password", + }, + KEY: { type: Scratch.ArgumentType.STRING, defaultValue: "key" }, + }, + }, + ], + }; + } + + async delay() { + const d = Math.random() * 500; + return new Promise((r) => setTimeout(r, d)); + } + + async setKey(args) { + await this.delay(); + const { KEY, VALUE } = args; + if (VALUE.length > 8000) return; + await fetch(`${this.api}/pin/${encodeURIComponent(KEY)}.json`, { + method: "PUT", + body: JSON.stringify(VALUE), + }); + } + + async getKey(args) { + await this.delay(); + const { KEY } = args; + const res = await fetch( + `${this.api}/pin/${encodeURIComponent(KEY)}.json` + ); + const data = await res.json(); + return data ?? ""; + } + + async deriveKey(password, salt) { + const enc = new TextEncoder(); + const keyMaterial = await crypto.subtle.importKey( + "raw", + enc.encode(password), + "PBKDF2", + false, + ["deriveKey"] + ); + return await crypto.subtle.deriveKey( + { + name: "PBKDF2", + salt, + iterations: 100000, + hash: "SHA-256", + }, + keyMaterial, + { name: "AES-GCM", length: 256 }, + false, + ["encrypt", "decrypt"] + ); + } + + async setKeyWithPassword(args) { + await this.delay(); + const { KEY, VALUE, PASSWORD } = args; + if (VALUE.length > 8000) return; + + const enc = new TextEncoder(); + const iv = crypto.getRandomValues(new Uint8Array(12)); + const salt = crypto.getRandomValues(new Uint8Array(16)); + const key = await this.deriveKey(PASSWORD, salt); + const encrypted = await crypto.subtle.encrypt( + { name: "AES-GCM", iv }, + key, + enc.encode(VALUE) + ); + + const fullPackage = { + iv: Array.from(iv), + salt: Array.from(salt), + data: Array.from(new Uint8Array(encrypted)), + }; + + await fetch(`${this.api}/cypher/${encodeURIComponent(KEY)}.json`, { + method: "PUT", + body: JSON.stringify(fullPackage), + }); + } + + async getKeyWithPassword(args) { + await this.delay(); + const { KEY, PASSWORD } = args; + + const res = await fetch( + `${this.api}/cypher/${encodeURIComponent(KEY)}.json` + ); + const encryptedPackage = await res.json(); + if ( + !encryptedPackage || + !encryptedPackage.data || + !encryptedPackage.iv || + !encryptedPackage.salt + ) + return ""; + + try { + const iv = new Uint8Array(encryptedPackage.iv); + const salt = new Uint8Array(encryptedPackage.salt); + const data = new Uint8Array(encryptedPackage.data); + const key = await this.deriveKey(PASSWORD, salt); + const decrypted = await crypto.subtle.decrypt( + { name: "AES-GCM", iv }, + key, + data + ); + return new TextDecoder().decode(decrypted); + } catch (e) { + return ""; + } + } + + async checkPassword(args) { + await this.delay(); + const { KEY, PASSWORD } = args; + + const res = await fetch( + `${this.api}/cypher/${encodeURIComponent(KEY)}.json` + ); + const encryptedPackage = await res.json(); + if ( + !encryptedPackage || + !encryptedPackage.data || + !encryptedPackage.iv || + !encryptedPackage.salt + ) + return false; + + try { + const iv = new Uint8Array(encryptedPackage.iv); + const salt = new Uint8Array(encryptedPackage.salt); + const data = new Uint8Array(encryptedPackage.data); + const key = await this.deriveKey(PASSWORD, salt); + await crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, data); + return true; + } catch (e) { + return false; + } + } + } + + Scratch.extensions.register(new FirebaseDB()); })(Scratch);