From 165204c254e8ec3c0fce25211370ddae516a4717 Mon Sep 17 00:00:00 2001 From: SkyBuilder1717 Date: Mon, 11 Aug 2025 14:25:32 +0300 Subject: [PATCH 01/11] New Extension --- extensions/SkyBuilder1717/SK17.js | 339 ++++++++++++++++++++++++++++++ extensions/extensions.json | 3 +- images/SkyBuilder1717/SK17.svg | 215 +++++++++++++++++++ 3 files changed, 556 insertions(+), 1 deletion(-) create mode 100644 extensions/SkyBuilder1717/SK17.js create mode 100644 images/SkyBuilder1717/SK17.svg diff --git a/extensions/SkyBuilder1717/SK17.js b/extensions/SkyBuilder1717/SK17.js new file mode 100644 index 0000000000..cc924a0e88 --- /dev/null +++ b/extensions/SkyBuilder1717/SK17.js @@ -0,0 +1,339 @@ +// Name: SK17 +// ID: SkyBuilder1717Encryption +// Description: Adds new encryption format: SK17. Useful for saving games and loading private data in compiled games. +// By: SkyBuilder1717 +// License: MIT + +(async function (Scratch) { + if (!Scratch.extensions.unsandboxed) throw new Error("SK17 must run unsandboxed!"); + + const SIG = new Uint8Array([83, 75, 49, 55]); + + function bytesToLatin1String(u8) { + const CHUNK = 0x8000; + let result = ''; + for (let i = 0; i < u8.length; i += CHUNK) { + const slice = u8.subarray(i, i + CHUNK); + result += String.fromCharCode.apply(null, slice); + } + return result; + } + + function latin1StringToBytes(str) { + const u8 = new Uint8Array(str.length); + for (let i = 0; i < str.length; i++) { + u8[i] = str.charCodeAt(i) & 0xFF; + } + return u8; + } + + function concat(...parts) { + const total = parts.reduce((s, p) => s + p.length, 0); + const out = new Uint8Array(total); + let off = 0; + for (const p of parts) { + out.set(p, off); + off += p.length; + } + return out; + } + + async function deriveKey(password, salt) { + const enc = new TextEncoder(); + const pwKey = await crypto.subtle.importKey( + "raw", + enc.encode(password), + { name: "PBKDF2" }, + false, + ["deriveKey"] + ); + return await crypto.subtle.deriveKey( + { + name: "PBKDF2", + salt: salt, + iterations: 150000, + hash: "SHA-256" + }, + pwKey, + { name: "AES-GCM", length: 256 }, + false, + ["encrypt", "decrypt"] + ); + } + + function xorEncrypt(data, password) { + const pwdBytes = new TextEncoder().encode(password); + const result = new Uint8Array(data.length); + for (let i = 0; i < data.length; i++) { + result[i] = data[i] ^ pwdBytes[i % pwdBytes.length]; + } + return result; + } + + function rotateBytes(data, _) { + const len = data.length; + if (len === 0) return data; + const rotated = new Uint8Array(len); + for (let i = 0; i < len; i++) { + rotated[(i + 1) % len] = data[i]; + } + return rotated; + } + + function xorWithConst(data, constant) { + const result = new Uint8Array(data.length); + for (let i = 0; i < data.length; i++) { + result[i] = data[i] ^ constant; + } + return result; + } + + const encryptionStages = [ + xorEncrypt, + rotateBytes, + xorWithConst + ]; + + function multiStageEncrypt(data, password) { + let encrypted = data; + for (const stage of encryptionStages) { + encrypted = stage(encrypted, password); + } + return encrypted; + } + + function multiStageDecrypt(data, password) { + let decrypted = data; + for (let i = encryptionStages.length - 1; i >= 0; i--) { + const stage = encryptionStages[i]; + if (stage === rotateBytes) { + const len = decrypted.length; + if (len > 0) { + const rotated = new Uint8Array(len); + for (let i = 0; i < len; i++) { + rotated[i] = decrypted[(i + 1) % len]; + } + decrypted = rotated; + } + } else { + decrypted = stage(decrypted, password); + } + } + return decrypted; + } + + class Extension { + getInfo() { + return { + id: "SkyBuilder1717Encryption", + name: "SK17", + color1: "#3f79bf", + color2: "#2c4d8a", + blocks: [ + { + opcode: "encrypt", + blockType: Scratch.BlockType.REPORTER, + text: "encrypt text [TEXT] with password [PASS]", + arguments: { + TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "Hello, World!" }, + PASS: { type: Scratch.ArgumentType.STRING, defaultValue: "password" } + } + }, + { + opcode: "decrypt", + blockType: Scratch.BlockType.REPORTER, + text: "decrypt text [TEXT] with password [PASS]", + arguments: { + TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" }, + PASS: { type: Scratch.ArgumentType.STRING, defaultValue: "password" } + } + }, + { + opcode: "base64Encode", + blockType: Scratch.BlockType.REPORTER, + text: "encode base64 [TEXT]", + arguments: { + TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "Hello" } + } + }, + { + opcode: "base64Decode", + blockType: Scratch.BlockType.REPORTER, + text: "decode base64 [TEXT]", + arguments: { + TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "SGVsbG8=" } + } + }, + { + opcode: "generatePassword", + blockType: Scratch.BlockType.REPORTER, + text: "generate password length [LENGTH] with chars [CHARS]", + arguments: { + LENGTH: { type: Scratch.ArgumentType.NUMBER, defaultValue: 8 }, + CHARS: { type: Scratch.ArgumentType.STRING, defaultValue: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" } + } + }, + { + opcode: "checkSignature", + blockType: Scratch.BlockType.BOOLEAN, + text: "verify signature [TEXT]", + arguments: { + TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" } + } + }, + { + opcode: "isValidEncrypted", + blockType: Scratch.BlockType.BOOLEAN, + text: "is encrypted data valid [TEXT]", + arguments: { + TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" } + } + }, + { + opcode: "saveFile", + blockType: Scratch.BlockType.REPORTER, + text: "save text [TEXT] as file [FILENAME]", + arguments: { + TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "Hello, World!" }, + FILENAME: { type: Scratch.ArgumentType.STRING, defaultValue: "file.enc" } + } + }, + { + opcode: "loadFile", + disableMonitor: true, + blockType: Scratch.BlockType.REPORTER, + text: "load file as .enc", + arguments: {} + } + ] + }; + } + + async encrypt(args) { + const password = args.PASS; + const data = new TextEncoder().encode(args.TEXT); + const salt = crypto.getRandomValues(new Uint8Array(16)); + const iv = crypto.getRandomValues(new Uint8Array(12)); + const key = await deriveKey(password, salt); + const cipherBuf = await crypto.subtle.encrypt({ name: "AES-GCM", iv: iv }, key, data); + let ciphertext = new Uint8Array(cipherBuf); + ciphertext = multiStageEncrypt(ciphertext, password); + const out = concat(SIG, salt, iv, ciphertext); + return bytesToLatin1String(out); + } + + async decrypt(args) { + const password = args.PASS; + const u8 = latin1StringToBytes(args.TEXT); + if (u8.length < SIG.length + 16 + 12 + 1) throw new Error("Invalid data"); + for (let i = 0; i < SIG.length; i++) { + if (u8[i] !== SIG[i]) throw new Error("Bad signature"); + } + let off = SIG.length; + const salt = u8.slice(off, off + 16); off += 16; + const iv = u8.slice(off, off + 12); off += 12; + let ciphertext = u8.slice(off); + ciphertext = multiStageDecrypt(ciphertext, password); + const key = await deriveKey(password, salt); + const plainBuf = await crypto.subtle.decrypt({ name: "AES-GCM", iv: iv }, key, ciphertext); + return new TextDecoder().decode(new Uint8Array(plainBuf)); + } + + base64Encode(args) { + const u8 = new TextEncoder().encode(args.TEXT); + let binary = ''; + u8.forEach(b => binary += String.fromCharCode(b)); + return btoa(binary); + } + + base64Decode(args) { + try { + const binary = atob(args.TEXT); + const u8 = new Uint8Array(binary.length); + for (let i = 0; i < binary.length; i++) { + u8[i] = binary.charCodeAt(i); + } + return new TextDecoder().decode(u8); + } catch { + return ""; + } + } + + generatePassword(args) { + const length = args.LENGTH; + const charset = args.CHARS; + let result = ""; + const chars = charset ? String(charset) : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + for (let i = 0; i < length; i++) { + const randIndex = Math.floor(Math.random() * chars.length); + result += chars.charAt(randIndex); + } + return result; + } + + checkSignature(args) { + const text = args.TEXT; + if (typeof text !== "string") return false; + if (text.length < SIG.length) return false; + for (let i = 0; i < SIG.length; i++) { + if (text.charCodeAt(i) !== SIG[i]) return false; + } + return true; + } + + isValidEncrypted(args) { + const text = args.TEXT; + if (typeof text !== "string") return false; + const u8 = latin1StringToBytes(text); + if (u8.length < SIG.length + 16 + 12 + 1) return false; + for (let i = 0; i < SIG.length; i++) { + if (u8[i] !== SIG[i]) return false; + } + return true; + } + + saveFile(args) { + const latin1String = args.TEXT; + const filename = args.FILENAME; + const u8 = latin1StringToBytes(latin1String); + const blob = new Blob([u8], { type: "application/octet-stream" }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = filename || "file.enc"; + document.body.appendChild(a); + a.click(); + setTimeout(() => { + URL.revokeObjectURL(url); + a.remove(); + }, 1000); + return filename || "file.enc"; + } + + loadFile() { + return new Promise((resolve) => { + const input = document.createElement("input"); + input.type = "file"; + input.accept = ".enc"; + input.style.display = "none"; + document.body.appendChild(input); + input.onchange = async () => { + if (!input.files || input.files.length === 0) { + document.body.removeChild(input); + resolve(""); + return; + } + const f = input.files[0]; + const ab = await f.arrayBuffer(); + const u8 = new Uint8Array(ab); + const s = bytesToLatin1String(u8); + document.body.removeChild(input); + resolve(s); + }; + input.click(); + }); + } + } + + Scratch.extensions.register(new Extension()); +})(Scratch); \ No newline at end of file diff --git a/extensions/extensions.json b/extensions/extensions.json index d8ed71e33d..5fa0609079 100644 --- a/extensions/extensions.json +++ b/extensions/extensions.json @@ -47,6 +47,7 @@ "XeroName/Deltatime", "ar", "encoding", + "SkyBuilder1717/SK17", "Lily/SoundExpanded", "Lily/TempVariables2", "Lily/MoreTimers", @@ -98,4 +99,4 @@ "gamejolt", "obviousAlexC/newgroundsIO", "Lily/McUtils" // McUtils should always be the last item. -] +] \ No newline at end of file diff --git a/images/SkyBuilder1717/SK17.svg b/images/SkyBuilder1717/SK17.svg new file mode 100644 index 0000000000..4a07dca219 --- /dev/null +++ b/images/SkyBuilder1717/SK17.svg @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + ÆÞñ´5¢2¼pÐ'n÷¾jÝ) + Hello, World! + + + + + SK17 + + + From b65a01b4adff7159fcbae2ebb12888385b29edde Mon Sep 17 00:00:00 2001 From: "DangoCat[bot]" Date: Mon, 11 Aug 2025 11:31:29 +0000 Subject: [PATCH 02/11] [Automated] Format code --- extensions/SkyBuilder1717/SK17.js | 634 ++++++++++++++++-------------- 1 file changed, 334 insertions(+), 300 deletions(-) diff --git a/extensions/SkyBuilder1717/SK17.js b/extensions/SkyBuilder1717/SK17.js index cc924a0e88..fec5ed1479 100644 --- a/extensions/SkyBuilder1717/SK17.js +++ b/extensions/SkyBuilder1717/SK17.js @@ -5,335 +5,369 @@ // License: MIT (async function (Scratch) { - if (!Scratch.extensions.unsandboxed) throw new Error("SK17 must run unsandboxed!"); + if (!Scratch.extensions.unsandboxed) + throw new Error("SK17 must run unsandboxed!"); - const SIG = new Uint8Array([83, 75, 49, 55]); + const SIG = new Uint8Array([83, 75, 49, 55]); - function bytesToLatin1String(u8) { - const CHUNK = 0x8000; - let result = ''; - for (let i = 0; i < u8.length; i += CHUNK) { - const slice = u8.subarray(i, i + CHUNK); - result += String.fromCharCode.apply(null, slice); - } - return result; + function bytesToLatin1String(u8) { + const CHUNK = 0x8000; + let result = ""; + for (let i = 0; i < u8.length; i += CHUNK) { + const slice = u8.subarray(i, i + CHUNK); + result += String.fromCharCode.apply(null, slice); } + return result; + } - function latin1StringToBytes(str) { - const u8 = new Uint8Array(str.length); - for (let i = 0; i < str.length; i++) { - u8[i] = str.charCodeAt(i) & 0xFF; - } - return u8; + function latin1StringToBytes(str) { + const u8 = new Uint8Array(str.length); + for (let i = 0; i < str.length; i++) { + u8[i] = str.charCodeAt(i) & 0xff; } + return u8; + } - function concat(...parts) { - const total = parts.reduce((s, p) => s + p.length, 0); - const out = new Uint8Array(total); - let off = 0; - for (const p of parts) { - out.set(p, off); - off += p.length; - } - return out; + function concat(...parts) { + const total = parts.reduce((s, p) => s + p.length, 0); + const out = new Uint8Array(total); + let off = 0; + for (const p of parts) { + out.set(p, off); + off += p.length; } + return out; + } - async function deriveKey(password, salt) { - const enc = new TextEncoder(); - const pwKey = await crypto.subtle.importKey( - "raw", - enc.encode(password), - { name: "PBKDF2" }, - false, - ["deriveKey"] - ); - return await crypto.subtle.deriveKey( - { - name: "PBKDF2", - salt: salt, - iterations: 150000, - hash: "SHA-256" - }, - pwKey, - { name: "AES-GCM", length: 256 }, - false, - ["encrypt", "decrypt"] - ); - } + async function deriveKey(password, salt) { + const enc = new TextEncoder(); + const pwKey = await crypto.subtle.importKey( + "raw", + enc.encode(password), + { name: "PBKDF2" }, + false, + ["deriveKey"] + ); + return await crypto.subtle.deriveKey( + { + name: "PBKDF2", + salt: salt, + iterations: 150000, + hash: "SHA-256", + }, + pwKey, + { name: "AES-GCM", length: 256 }, + false, + ["encrypt", "decrypt"] + ); + } - function xorEncrypt(data, password) { - const pwdBytes = new TextEncoder().encode(password); - const result = new Uint8Array(data.length); - for (let i = 0; i < data.length; i++) { - result[i] = data[i] ^ pwdBytes[i % pwdBytes.length]; - } - return result; + function xorEncrypt(data, password) { + const pwdBytes = new TextEncoder().encode(password); + const result = new Uint8Array(data.length); + for (let i = 0; i < data.length; i++) { + result[i] = data[i] ^ pwdBytes[i % pwdBytes.length]; } - - function rotateBytes(data, _) { - const len = data.length; - if (len === 0) return data; - const rotated = new Uint8Array(len); - for (let i = 0; i < len; i++) { - rotated[(i + 1) % len] = data[i]; - } - return rotated; + return result; + } + + function rotateBytes(data, _) { + const len = data.length; + if (len === 0) return data; + const rotated = new Uint8Array(len); + for (let i = 0; i < len; i++) { + rotated[(i + 1) % len] = data[i]; } + return rotated; + } - function xorWithConst(data, constant) { - const result = new Uint8Array(data.length); - for (let i = 0; i < data.length; i++) { - result[i] = data[i] ^ constant; - } - return result; + function xorWithConst(data, constant) { + const result = new Uint8Array(data.length); + for (let i = 0; i < data.length; i++) { + result[i] = data[i] ^ constant; } + return result; + } - const encryptionStages = [ - xorEncrypt, - rotateBytes, - xorWithConst - ]; + const encryptionStages = [xorEncrypt, rotateBytes, xorWithConst]; - function multiStageEncrypt(data, password) { - let encrypted = data; - for (const stage of encryptionStages) { - encrypted = stage(encrypted, password); - } - return encrypted; + function multiStageEncrypt(data, password) { + let encrypted = data; + for (const stage of encryptionStages) { + encrypted = stage(encrypted, password); } + return encrypted; + } - function multiStageDecrypt(data, password) { - let decrypted = data; - for (let i = encryptionStages.length - 1; i >= 0; i--) { - const stage = encryptionStages[i]; - if (stage === rotateBytes) { - const len = decrypted.length; - if (len > 0) { - const rotated = new Uint8Array(len); - for (let i = 0; i < len; i++) { - rotated[i] = decrypted[(i + 1) % len]; - } - decrypted = rotated; - } - } else { - decrypted = stage(decrypted, password); - } + function multiStageDecrypt(data, password) { + let decrypted = data; + for (let i = encryptionStages.length - 1; i >= 0; i--) { + const stage = encryptionStages[i]; + if (stage === rotateBytes) { + const len = decrypted.length; + if (len > 0) { + const rotated = new Uint8Array(len); + for (let i = 0; i < len; i++) { + rotated[i] = decrypted[(i + 1) % len]; + } + decrypted = rotated; } - return decrypted; + } else { + decrypted = stage(decrypted, password); + } } + return decrypted; + } - class Extension { - getInfo() { - return { - id: "SkyBuilder1717Encryption", - name: "SK17", - color1: "#3f79bf", - color2: "#2c4d8a", - blocks: [ - { - opcode: "encrypt", - blockType: Scratch.BlockType.REPORTER, - text: "encrypt text [TEXT] with password [PASS]", - arguments: { - TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "Hello, World!" }, - PASS: { type: Scratch.ArgumentType.STRING, defaultValue: "password" } - } - }, - { - opcode: "decrypt", - blockType: Scratch.BlockType.REPORTER, - text: "decrypt text [TEXT] with password [PASS]", - arguments: { - TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" }, - PASS: { type: Scratch.ArgumentType.STRING, defaultValue: "password" } - } - }, - { - opcode: "base64Encode", - blockType: Scratch.BlockType.REPORTER, - text: "encode base64 [TEXT]", - arguments: { - TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "Hello" } - } - }, - { - opcode: "base64Decode", - blockType: Scratch.BlockType.REPORTER, - text: "decode base64 [TEXT]", - arguments: { - TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "SGVsbG8=" } - } - }, - { - opcode: "generatePassword", - blockType: Scratch.BlockType.REPORTER, - text: "generate password length [LENGTH] with chars [CHARS]", - arguments: { - LENGTH: { type: Scratch.ArgumentType.NUMBER, defaultValue: 8 }, - CHARS: { type: Scratch.ArgumentType.STRING, defaultValue: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" } - } - }, - { - opcode: "checkSignature", - blockType: Scratch.BlockType.BOOLEAN, - text: "verify signature [TEXT]", - arguments: { - TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" } - } - }, - { - opcode: "isValidEncrypted", - blockType: Scratch.BlockType.BOOLEAN, - text: "is encrypted data valid [TEXT]", - arguments: { - TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" } - } - }, - { - opcode: "saveFile", - blockType: Scratch.BlockType.REPORTER, - text: "save text [TEXT] as file [FILENAME]", - arguments: { - TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "Hello, World!" }, - FILENAME: { type: Scratch.ArgumentType.STRING, defaultValue: "file.enc" } - } - }, - { - opcode: "loadFile", - disableMonitor: true, - blockType: Scratch.BlockType.REPORTER, - text: "load file as .enc", - arguments: {} - } - ] - }; - } + class Extension { + getInfo() { + return { + id: "SkyBuilder1717Encryption", + name: "SK17", + color1: "#3f79bf", + color2: "#2c4d8a", + blocks: [ + { + opcode: "encrypt", + blockType: Scratch.BlockType.REPORTER, + text: "encrypt text [TEXT] with password [PASS]", + arguments: { + TEXT: { + type: Scratch.ArgumentType.STRING, + defaultValue: "Hello, World!", + }, + PASS: { + type: Scratch.ArgumentType.STRING, + defaultValue: "password", + }, + }, + }, + { + opcode: "decrypt", + blockType: Scratch.BlockType.REPORTER, + text: "decrypt text [TEXT] with password [PASS]", + arguments: { + TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" }, + PASS: { + type: Scratch.ArgumentType.STRING, + defaultValue: "password", + }, + }, + }, + { + opcode: "base64Encode", + blockType: Scratch.BlockType.REPORTER, + text: "encode base64 [TEXT]", + arguments: { + TEXT: { + type: Scratch.ArgumentType.STRING, + defaultValue: "Hello", + }, + }, + }, + { + opcode: "base64Decode", + blockType: Scratch.BlockType.REPORTER, + text: "decode base64 [TEXT]", + arguments: { + TEXT: { + type: Scratch.ArgumentType.STRING, + defaultValue: "SGVsbG8=", + }, + }, + }, + { + opcode: "generatePassword", + blockType: Scratch.BlockType.REPORTER, + text: "generate password length [LENGTH] with chars [CHARS]", + arguments: { + LENGTH: { type: Scratch.ArgumentType.NUMBER, defaultValue: 8 }, + CHARS: { + type: Scratch.ArgumentType.STRING, + defaultValue: + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + }, + }, + }, + { + opcode: "checkSignature", + blockType: Scratch.BlockType.BOOLEAN, + text: "verify signature [TEXT]", + arguments: { + TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" }, + }, + }, + { + opcode: "isValidEncrypted", + blockType: Scratch.BlockType.BOOLEAN, + text: "is encrypted data valid [TEXT]", + arguments: { + TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" }, + }, + }, + { + opcode: "saveFile", + blockType: Scratch.BlockType.REPORTER, + text: "save text [TEXT] as file [FILENAME]", + arguments: { + TEXT: { + type: Scratch.ArgumentType.STRING, + defaultValue: "Hello, World!", + }, + FILENAME: { + type: Scratch.ArgumentType.STRING, + defaultValue: "file.enc", + }, + }, + }, + { + opcode: "loadFile", + disableMonitor: true, + blockType: Scratch.BlockType.REPORTER, + text: "load file as .enc", + arguments: {}, + }, + ], + }; + } - async encrypt(args) { - const password = args.PASS; - const data = new TextEncoder().encode(args.TEXT); - const salt = crypto.getRandomValues(new Uint8Array(16)); - const iv = crypto.getRandomValues(new Uint8Array(12)); - const key = await deriveKey(password, salt); - const cipherBuf = await crypto.subtle.encrypt({ name: "AES-GCM", iv: iv }, key, data); - let ciphertext = new Uint8Array(cipherBuf); - ciphertext = multiStageEncrypt(ciphertext, password); - const out = concat(SIG, salt, iv, ciphertext); - return bytesToLatin1String(out); - } + async encrypt(args) { + const password = args.PASS; + const data = new TextEncoder().encode(args.TEXT); + const salt = crypto.getRandomValues(new Uint8Array(16)); + const iv = crypto.getRandomValues(new Uint8Array(12)); + const key = await deriveKey(password, salt); + const cipherBuf = await crypto.subtle.encrypt( + { name: "AES-GCM", iv: iv }, + key, + data + ); + let ciphertext = new Uint8Array(cipherBuf); + ciphertext = multiStageEncrypt(ciphertext, password); + const out = concat(SIG, salt, iv, ciphertext); + return bytesToLatin1String(out); + } - async decrypt(args) { - const password = args.PASS; - const u8 = latin1StringToBytes(args.TEXT); - if (u8.length < SIG.length + 16 + 12 + 1) throw new Error("Invalid data"); - for (let i = 0; i < SIG.length; i++) { - if (u8[i] !== SIG[i]) throw new Error("Bad signature"); - } - let off = SIG.length; - const salt = u8.slice(off, off + 16); off += 16; - const iv = u8.slice(off, off + 12); off += 12; - let ciphertext = u8.slice(off); - ciphertext = multiStageDecrypt(ciphertext, password); - const key = await deriveKey(password, salt); - const plainBuf = await crypto.subtle.decrypt({ name: "AES-GCM", iv: iv }, key, ciphertext); - return new TextDecoder().decode(new Uint8Array(plainBuf)); - } + async decrypt(args) { + const password = args.PASS; + const u8 = latin1StringToBytes(args.TEXT); + if (u8.length < SIG.length + 16 + 12 + 1) throw new Error("Invalid data"); + for (let i = 0; i < SIG.length; i++) { + if (u8[i] !== SIG[i]) throw new Error("Bad signature"); + } + let off = SIG.length; + const salt = u8.slice(off, off + 16); + off += 16; + const iv = u8.slice(off, off + 12); + off += 12; + let ciphertext = u8.slice(off); + ciphertext = multiStageDecrypt(ciphertext, password); + const key = await deriveKey(password, salt); + const plainBuf = await crypto.subtle.decrypt( + { name: "AES-GCM", iv: iv }, + key, + ciphertext + ); + return new TextDecoder().decode(new Uint8Array(plainBuf)); + } - base64Encode(args) { - const u8 = new TextEncoder().encode(args.TEXT); - let binary = ''; - u8.forEach(b => binary += String.fromCharCode(b)); - return btoa(binary); - } + base64Encode(args) { + const u8 = new TextEncoder().encode(args.TEXT); + let binary = ""; + u8.forEach((b) => (binary += String.fromCharCode(b))); + return btoa(binary); + } - base64Decode(args) { - try { - const binary = atob(args.TEXT); - const u8 = new Uint8Array(binary.length); - for (let i = 0; i < binary.length; i++) { - u8[i] = binary.charCodeAt(i); - } - return new TextDecoder().decode(u8); - } catch { - return ""; - } + base64Decode(args) { + try { + const binary = atob(args.TEXT); + const u8 = new Uint8Array(binary.length); + for (let i = 0; i < binary.length; i++) { + u8[i] = binary.charCodeAt(i); } + return new TextDecoder().decode(u8); + } catch { + return ""; + } + } - generatePassword(args) { - const length = args.LENGTH; - const charset = args.CHARS; - let result = ""; - const chars = charset ? String(charset) : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - for (let i = 0; i < length; i++) { - const randIndex = Math.floor(Math.random() * chars.length); - result += chars.charAt(randIndex); - } - return result; - } + generatePassword(args) { + const length = args.LENGTH; + const charset = args.CHARS; + let result = ""; + const chars = charset + ? String(charset) + : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + for (let i = 0; i < length; i++) { + const randIndex = Math.floor(Math.random() * chars.length); + result += chars.charAt(randIndex); + } + return result; + } - checkSignature(args) { - const text = args.TEXT; - if (typeof text !== "string") return false; - if (text.length < SIG.length) return false; - for (let i = 0; i < SIG.length; i++) { - if (text.charCodeAt(i) !== SIG[i]) return false; - } - return true; - } + checkSignature(args) { + const text = args.TEXT; + if (typeof text !== "string") return false; + if (text.length < SIG.length) return false; + for (let i = 0; i < SIG.length; i++) { + if (text.charCodeAt(i) !== SIG[i]) return false; + } + return true; + } - isValidEncrypted(args) { - const text = args.TEXT; - if (typeof text !== "string") return false; - const u8 = latin1StringToBytes(text); - if (u8.length < SIG.length + 16 + 12 + 1) return false; - for (let i = 0; i < SIG.length; i++) { - if (u8[i] !== SIG[i]) return false; - } - return true; - } + isValidEncrypted(args) { + const text = args.TEXT; + if (typeof text !== "string") return false; + const u8 = latin1StringToBytes(text); + if (u8.length < SIG.length + 16 + 12 + 1) return false; + for (let i = 0; i < SIG.length; i++) { + if (u8[i] !== SIG[i]) return false; + } + return true; + } - saveFile(args) { - const latin1String = args.TEXT; - const filename = args.FILENAME; - const u8 = latin1StringToBytes(latin1String); - const blob = new Blob([u8], { type: "application/octet-stream" }); - const url = URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = filename || "file.enc"; - document.body.appendChild(a); - a.click(); - setTimeout(() => { - URL.revokeObjectURL(url); - a.remove(); - }, 1000); - return filename || "file.enc"; - } + saveFile(args) { + const latin1String = args.TEXT; + const filename = args.FILENAME; + const u8 = latin1StringToBytes(latin1String); + const blob = new Blob([u8], { type: "application/octet-stream" }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = filename || "file.enc"; + document.body.appendChild(a); + a.click(); + setTimeout(() => { + URL.revokeObjectURL(url); + a.remove(); + }, 1000); + return filename || "file.enc"; + } - loadFile() { - return new Promise((resolve) => { - const input = document.createElement("input"); - input.type = "file"; - input.accept = ".enc"; - input.style.display = "none"; - document.body.appendChild(input); - input.onchange = async () => { - if (!input.files || input.files.length === 0) { - document.body.removeChild(input); - resolve(""); - return; - } - const f = input.files[0]; - const ab = await f.arrayBuffer(); - const u8 = new Uint8Array(ab); - const s = bytesToLatin1String(u8); - document.body.removeChild(input); - resolve(s); - }; - input.click(); - }); - } + loadFile() { + return new Promise((resolve) => { + const input = document.createElement("input"); + input.type = "file"; + input.accept = ".enc"; + input.style.display = "none"; + document.body.appendChild(input); + input.onchange = async () => { + if (!input.files || input.files.length === 0) { + document.body.removeChild(input); + resolve(""); + return; + } + const f = input.files[0]; + const ab = await f.arrayBuffer(); + const u8 = new Uint8Array(ab); + const s = bytesToLatin1String(u8); + document.body.removeChild(input); + resolve(s); + }; + input.click(); + }); } + } - Scratch.extensions.register(new Extension()); -})(Scratch); \ No newline at end of file + Scratch.extensions.register(new Extension()); +})(Scratch); From ae3795ec112878c6b2a9311be03c63dc08d76d0e Mon Sep 17 00:00:00 2001 From: SkyBuilder1717 Date: Mon, 11 Aug 2025 14:35:15 +0300 Subject: [PATCH 03/11] Text to Path --- images/SkyBuilder1717/SK17.svg | 52 +++++++++++----------------------- 1 file changed, 17 insertions(+), 35 deletions(-) diff --git a/images/SkyBuilder1717/SK17.svg b/images/SkyBuilder1717/SK17.svg index 4a07dca219..579ca99415 100644 --- a/images/SkyBuilder1717/SK17.svg +++ b/images/SkyBuilder1717/SK17.svg @@ -25,14 +25,14 @@ inkscape:deskcolor="#d1d1d1" inkscape:document-units="mm" inkscape:zoom="0.71891835" - inkscape:cx="620.37643" + inkscape:cx="621.07192" inkscape:cy="75.808331" inkscape:window-width="1920" inkscape:window-height="1009" inkscape:window-x="-8" inkscape:window-y="-8" inkscape:window-maximized="1" - inkscape:current-layer="layer2" /> + inkscape:current-layer="layer1" /> - ÆÞñ´5¢2¼pÐ'n÷¾jÝ) - Hello, World! + + - SK17 + From 4c62ea2fe8fc31d18c658061417f085a7dde476e Mon Sep 17 00:00:00 2001 From: SkyBuilder1717 Date: Mon, 11 Aug 2025 14:38:46 +0300 Subject: [PATCH 04/11] 'use strict'; Scratch.translate; await; --- extensions/SkyBuilder1717/SK17.js | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/extensions/SkyBuilder1717/SK17.js b/extensions/SkyBuilder1717/SK17.js index fec5ed1479..f0b7d28fcd 100644 --- a/extensions/SkyBuilder1717/SK17.js +++ b/extensions/SkyBuilder1717/SK17.js @@ -5,6 +5,8 @@ // License: MIT (async function (Scratch) { + 'use strict'; + if (!Scratch.extensions.unsandboxed) throw new Error("SK17 must run unsandboxed!"); @@ -123,14 +125,14 @@ getInfo() { return { id: "SkyBuilder1717Encryption", - name: "SK17", + name: Scratch.translate("SK17"), color1: "#3f79bf", color2: "#2c4d8a", blocks: [ { opcode: "encrypt", blockType: Scratch.BlockType.REPORTER, - text: "encrypt text [TEXT] with password [PASS]", + text: Scratch.translate("encrypt text [TEXT] with password [PASS]"), arguments: { TEXT: { type: Scratch.ArgumentType.STRING, @@ -145,7 +147,7 @@ { opcode: "decrypt", blockType: Scratch.BlockType.REPORTER, - text: "decrypt text [TEXT] with password [PASS]", + text: Scratch.translate("decrypt text [TEXT] with password [PASS]"), arguments: { TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" }, PASS: { @@ -157,7 +159,7 @@ { opcode: "base64Encode", blockType: Scratch.BlockType.REPORTER, - text: "encode base64 [TEXT]", + text: Scratch.translate("encode base64 [TEXT]"), arguments: { TEXT: { type: Scratch.ArgumentType.STRING, @@ -168,7 +170,7 @@ { opcode: "base64Decode", blockType: Scratch.BlockType.REPORTER, - text: "decode base64 [TEXT]", + text: Scratch.translate("decode base64 [TEXT]"), arguments: { TEXT: { type: Scratch.ArgumentType.STRING, @@ -179,7 +181,7 @@ { opcode: "generatePassword", blockType: Scratch.BlockType.REPORTER, - text: "generate password length [LENGTH] with chars [CHARS]", + text: Scratch.translate("generate password length [LENGTH] with chars [CHARS]"), arguments: { LENGTH: { type: Scratch.ArgumentType.NUMBER, defaultValue: 8 }, CHARS: { @@ -192,7 +194,7 @@ { opcode: "checkSignature", blockType: Scratch.BlockType.BOOLEAN, - text: "verify signature [TEXT]", + text: Scratch.translate("verify signature [TEXT]"), arguments: { TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" }, }, @@ -200,7 +202,7 @@ { opcode: "isValidEncrypted", blockType: Scratch.BlockType.BOOLEAN, - text: "is encrypted data valid [TEXT]", + text: Scratch.translate("is encrypted data valid [TEXT]"), arguments: { TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" }, }, @@ -208,7 +210,7 @@ { opcode: "saveFile", blockType: Scratch.BlockType.REPORTER, - text: "save text [TEXT] as file [FILENAME]", + text: Scratch.translate("save text [TEXT] as file [FILENAME]"), arguments: { TEXT: { type: Scratch.ArgumentType.STRING, @@ -224,7 +226,7 @@ opcode: "loadFile", disableMonitor: true, blockType: Scratch.BlockType.REPORTER, - text: "load file as .enc", + text: Scratch.translate("load file as .enc"), arguments: {}, }, ], @@ -245,7 +247,7 @@ let ciphertext = new Uint8Array(cipherBuf); ciphertext = multiStageEncrypt(ciphertext, password); const out = concat(SIG, salt, iv, ciphertext); - return bytesToLatin1String(out); + return await bytesToLatin1String(out); } async decrypt(args) { @@ -268,7 +270,7 @@ key, ciphertext ); - return new TextDecoder().decode(new Uint8Array(plainBuf)); + return await new TextDecoder().decode(new Uint8Array(plainBuf)); } base64Encode(args) { From 2d81dff39b430716dc801c745759315dcab6a68b Mon Sep 17 00:00:00 2001 From: SkyBuilder1717 Date: Mon, 11 Aug 2025 14:40:36 +0300 Subject: [PATCH 05/11] Fix async function (Scratch) --- extensions/SkyBuilder1717/SK17.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/SkyBuilder1717/SK17.js b/extensions/SkyBuilder1717/SK17.js index f0b7d28fcd..c80f680231 100644 --- a/extensions/SkyBuilder1717/SK17.js +++ b/extensions/SkyBuilder1717/SK17.js @@ -4,7 +4,7 @@ // By: SkyBuilder1717 // License: MIT -(async function (Scratch) { +(function (Scratch) { 'use strict'; if (!Scratch.extensions.unsandboxed) From f525d8c4a1007ce8bea73783aa8c6268387d698c Mon Sep 17 00:00:00 2001 From: "DangoCat[bot]" Date: Mon, 11 Aug 2025 11:41:42 +0000 Subject: [PATCH 06/11] [Automated] Format code --- extensions/SkyBuilder1717/SK17.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/extensions/SkyBuilder1717/SK17.js b/extensions/SkyBuilder1717/SK17.js index c80f680231..a42f42d447 100644 --- a/extensions/SkyBuilder1717/SK17.js +++ b/extensions/SkyBuilder1717/SK17.js @@ -5,7 +5,7 @@ // License: MIT (function (Scratch) { - 'use strict'; + "use strict"; if (!Scratch.extensions.unsandboxed) throw new Error("SK17 must run unsandboxed!"); @@ -132,7 +132,7 @@ { opcode: "encrypt", blockType: Scratch.BlockType.REPORTER, - text: Scratch.translate("encrypt text [TEXT] with password [PASS]"), + text: Scratch.translate("encrypt text [TEXT] with password [PASS]"), arguments: { TEXT: { type: Scratch.ArgumentType.STRING, @@ -147,7 +147,7 @@ { opcode: "decrypt", blockType: Scratch.BlockType.REPORTER, - text: Scratch.translate("decrypt text [TEXT] with password [PASS]"), + text: Scratch.translate("decrypt text [TEXT] with password [PASS]"), arguments: { TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" }, PASS: { @@ -159,7 +159,7 @@ { opcode: "base64Encode", blockType: Scratch.BlockType.REPORTER, - text: Scratch.translate("encode base64 [TEXT]"), + text: Scratch.translate("encode base64 [TEXT]"), arguments: { TEXT: { type: Scratch.ArgumentType.STRING, @@ -170,7 +170,7 @@ { opcode: "base64Decode", blockType: Scratch.BlockType.REPORTER, - text: Scratch.translate("decode base64 [TEXT]"), + text: Scratch.translate("decode base64 [TEXT]"), arguments: { TEXT: { type: Scratch.ArgumentType.STRING, @@ -181,7 +181,9 @@ { opcode: "generatePassword", blockType: Scratch.BlockType.REPORTER, - text: Scratch.translate("generate password length [LENGTH] with chars [CHARS]"), + text: Scratch.translate( + "generate password length [LENGTH] with chars [CHARS]" + ), arguments: { LENGTH: { type: Scratch.ArgumentType.NUMBER, defaultValue: 8 }, CHARS: { @@ -194,7 +196,7 @@ { opcode: "checkSignature", blockType: Scratch.BlockType.BOOLEAN, - text: Scratch.translate("verify signature [TEXT]"), + text: Scratch.translate("verify signature [TEXT]"), arguments: { TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" }, }, @@ -202,7 +204,7 @@ { opcode: "isValidEncrypted", blockType: Scratch.BlockType.BOOLEAN, - text: Scratch.translate("is encrypted data valid [TEXT]"), + text: Scratch.translate("is encrypted data valid [TEXT]"), arguments: { TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" }, }, @@ -210,7 +212,7 @@ { opcode: "saveFile", blockType: Scratch.BlockType.REPORTER, - text: Scratch.translate("save text [TEXT] as file [FILENAME]"), + text: Scratch.translate("save text [TEXT] as file [FILENAME]"), arguments: { TEXT: { type: Scratch.ArgumentType.STRING, From 572c01fcbb97934bf9bfcaf224747a675abf7f17 Mon Sep 17 00:00:00 2001 From: BlackImpostor <106878493+SkyBuilder1717@users.noreply.github.com> Date: Tue, 9 Sep 2025 08:20:47 +0300 Subject: [PATCH 07/11] Update SK17.js --- extensions/SkyBuilder1717/SK17.js | 137 +++++------------------------- 1 file changed, 19 insertions(+), 118 deletions(-) diff --git a/extensions/SkyBuilder1717/SK17.js b/extensions/SkyBuilder1717/SK17.js index a42f42d447..2ad5e0a879 100644 --- a/extensions/SkyBuilder1717/SK17.js +++ b/extensions/SkyBuilder1717/SK17.js @@ -136,13 +136,13 @@ arguments: { TEXT: { type: Scratch.ArgumentType.STRING, - defaultValue: "Hello, World!", + defaultValue: "Hello, World!" }, PASS: { type: Scratch.ArgumentType.STRING, - defaultValue: "password", - }, - }, + defaultValue: "password" + } + } }, { opcode: "decrypt", @@ -152,86 +152,43 @@ TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" }, PASS: { type: Scratch.ArgumentType.STRING, - defaultValue: "password", - }, - }, + defaultValue: "password" + } + } }, { opcode: "base64Encode", blockType: Scratch.BlockType.REPORTER, - text: Scratch.translate("encode base64 [TEXT]"), + text: "encode base64 bytes [TEXT]", arguments: { - TEXT: { - type: Scratch.ArgumentType.STRING, - defaultValue: "Hello", - }, - }, + TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "Hello" } + } }, { opcode: "base64Decode", blockType: Scratch.BlockType.REPORTER, - text: Scratch.translate("decode base64 [TEXT]"), + text: "decode base64 bytes [TEXT]", arguments: { - TEXT: { - type: Scratch.ArgumentType.STRING, - defaultValue: "SGVsbG8=", - }, - }, - }, - { - opcode: "generatePassword", - blockType: Scratch.BlockType.REPORTER, - text: Scratch.translate( - "generate password length [LENGTH] with chars [CHARS]" - ), - arguments: { - LENGTH: { type: Scratch.ArgumentType.NUMBER, defaultValue: 8 }, - CHARS: { - type: Scratch.ArgumentType.STRING, - defaultValue: - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", - }, - }, + TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "SGVsbG8=" } + } }, { opcode: "checkSignature", blockType: Scratch.BlockType.BOOLEAN, text: Scratch.translate("verify signature [TEXT]"), arguments: { - TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" }, - }, + TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" } + } }, { opcode: "isValidEncrypted", blockType: Scratch.BlockType.BOOLEAN, text: Scratch.translate("is encrypted data valid [TEXT]"), arguments: { - TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" }, - }, - }, - { - opcode: "saveFile", - blockType: Scratch.BlockType.REPORTER, - text: Scratch.translate("save text [TEXT] as file [FILENAME]"), - arguments: { - TEXT: { - type: Scratch.ArgumentType.STRING, - defaultValue: "Hello, World!", - }, - FILENAME: { - type: Scratch.ArgumentType.STRING, - defaultValue: "file.enc", - }, - }, - }, - { - opcode: "loadFile", - disableMonitor: true, - blockType: Scratch.BlockType.REPORTER, - text: Scratch.translate("load file as .enc"), - arguments: {}, - }, - ], + TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" } + } + } + ] }; } @@ -295,20 +252,6 @@ } } - generatePassword(args) { - const length = args.LENGTH; - const charset = args.CHARS; - let result = ""; - const chars = charset - ? String(charset) - : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - for (let i = 0; i < length; i++) { - const randIndex = Math.floor(Math.random() * chars.length); - result += chars.charAt(randIndex); - } - return result; - } - checkSignature(args) { const text = args.TEXT; if (typeof text !== "string") return false; @@ -329,48 +272,6 @@ } return true; } - - saveFile(args) { - const latin1String = args.TEXT; - const filename = args.FILENAME; - const u8 = latin1StringToBytes(latin1String); - const blob = new Blob([u8], { type: "application/octet-stream" }); - const url = URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = filename || "file.enc"; - document.body.appendChild(a); - a.click(); - setTimeout(() => { - URL.revokeObjectURL(url); - a.remove(); - }, 1000); - return filename || "file.enc"; - } - - loadFile() { - return new Promise((resolve) => { - const input = document.createElement("input"); - input.type = "file"; - input.accept = ".enc"; - input.style.display = "none"; - document.body.appendChild(input); - input.onchange = async () => { - if (!input.files || input.files.length === 0) { - document.body.removeChild(input); - resolve(""); - return; - } - const f = input.files[0]; - const ab = await f.arrayBuffer(); - const u8 = new Uint8Array(ab); - const s = bytesToLatin1String(u8); - document.body.removeChild(input); - resolve(s); - }; - input.click(); - }); - } } Scratch.extensions.register(new Extension()); From 1598145c9252b3e296a0cc9bd2749e31d136ec47 Mon Sep 17 00:00:00 2001 From: BlackImpostor <106878493+SkyBuilder1717@users.noreply.github.com> Date: Tue, 9 Sep 2025 08:25:16 +0300 Subject: [PATCH 08/11] Scratch.translate --- extensions/SkyBuilder1717/SK17.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/SkyBuilder1717/SK17.js b/extensions/SkyBuilder1717/SK17.js index 2ad5e0a879..08b3fb5e27 100644 --- a/extensions/SkyBuilder1717/SK17.js +++ b/extensions/SkyBuilder1717/SK17.js @@ -159,7 +159,7 @@ { opcode: "base64Encode", blockType: Scratch.BlockType.REPORTER, - text: "encode base64 bytes [TEXT]", + text: Scratch.translate("encode base64 bytes [TEXT]"), arguments: { TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "Hello" } } @@ -167,7 +167,7 @@ { opcode: "base64Decode", blockType: Scratch.BlockType.REPORTER, - text: "decode base64 bytes [TEXT]", + text: Scratch.translate("decode base64 bytes [TEXT]"), arguments: { TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "SGVsbG8=" } } From d95b61102b5b6a9639572ce7bd35da78ceb93015 Mon Sep 17 00:00:00 2001 From: "DangoCat[bot]" Date: Tue, 9 Sep 2025 05:26:25 +0000 Subject: [PATCH 09/11] [Automated] Format code --- extensions/SkyBuilder1717/SK17.js | 40 ++++++++++++++++++------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/extensions/SkyBuilder1717/SK17.js b/extensions/SkyBuilder1717/SK17.js index 08b3fb5e27..9680d52fbc 100644 --- a/extensions/SkyBuilder1717/SK17.js +++ b/extensions/SkyBuilder1717/SK17.js @@ -136,13 +136,13 @@ arguments: { TEXT: { type: Scratch.ArgumentType.STRING, - defaultValue: "Hello, World!" + defaultValue: "Hello, World!", }, PASS: { type: Scratch.ArgumentType.STRING, - defaultValue: "password" - } - } + defaultValue: "password", + }, + }, }, { opcode: "decrypt", @@ -152,43 +152,49 @@ TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" }, PASS: { type: Scratch.ArgumentType.STRING, - defaultValue: "password" - } - } + defaultValue: "password", + }, + }, }, { opcode: "base64Encode", blockType: Scratch.BlockType.REPORTER, text: Scratch.translate("encode base64 bytes [TEXT]"), arguments: { - TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "Hello" } - } + TEXT: { + type: Scratch.ArgumentType.STRING, + defaultValue: "Hello", + }, + }, }, { opcode: "base64Decode", blockType: Scratch.BlockType.REPORTER, text: Scratch.translate("decode base64 bytes [TEXT]"), arguments: { - TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "SGVsbG8=" } - } + TEXT: { + type: Scratch.ArgumentType.STRING, + defaultValue: "SGVsbG8=", + }, + }, }, { opcode: "checkSignature", blockType: Scratch.BlockType.BOOLEAN, text: Scratch.translate("verify signature [TEXT]"), arguments: { - TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" } - } + TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" }, + }, }, { opcode: "isValidEncrypted", blockType: Scratch.BlockType.BOOLEAN, text: Scratch.translate("is encrypted data valid [TEXT]"), arguments: { - TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" } - } - } - ] + TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "" }, + }, + }, + ], }; } From f7ac81956d3ca9a33831a5b3f335bf6edb4555b3 Mon Sep 17 00:00:00 2001 From: BlackImpostor <106878493+SkyBuilder1717@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:11:43 +0300 Subject: [PATCH 10/11] Add files via upload --- images/SkyBuilder1717/SK17.svg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/images/SkyBuilder1717/SK17.svg b/images/SkyBuilder1717/SK17.svg index 579ca99415..8aa64eb8b6 100644 --- a/images/SkyBuilder1717/SK17.svg +++ b/images/SkyBuilder1717/SK17.svg @@ -159,10 +159,10 @@ style="font-weight:bold;font-size:12.0376px;font-family:Arial;-inkscape-font-specification:'Arial Bold';fill:#ffffff;stroke-width:10.0313;stroke-linejoin:round" aria-label="ÆÞñ´5¢2¼pÐ'n÷¾jÝ)" /> + aria-label="🥲😧😦😛" /> Date: Wed, 17 Sep 2025 15:47:46 +0300 Subject: [PATCH 11/11] Update extensions/SkyBuilder1717/SK17.js Co-authored-by: Brackets-Coder <142950368+Brackets-Coder@users.noreply.github.com> --- extensions/SkyBuilder1717/SK17.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/SkyBuilder1717/SK17.js b/extensions/SkyBuilder1717/SK17.js index 9680d52fbc..1a5ea32a6f 100644 --- a/extensions/SkyBuilder1717/SK17.js +++ b/extensions/SkyBuilder1717/SK17.js @@ -1,4 +1,4 @@ -// Name: SK17 +// Name: Encryption // ID: SkyBuilder1717Encryption // Description: Adds new encryption format: SK17. Useful for saving games and loading private data in compiled games. // By: SkyBuilder1717