diff --git a/src/lib/auth.js b/src/lib/auth.js index cf4fa33c9..07fad9e50 100644 --- a/src/lib/auth.js +++ b/src/lib/auth.js @@ -1,4 +1,5 @@ import config from "./config"; +import { maskCredential, unmaskCredential } from "../security/security"; /** * @typedef {object} User @@ -43,6 +44,51 @@ const loginEvents = { }, }; +/** Function for get the object of user under the Server, + * clone the structure and mask in the Strings. + */ +function secureUserObject(user) { + if (!user) return null; + + const secured = { ...user }; + + // Array with String Properties of Object + const textProperties = [ + "name", "role", "email", "github", "website", + "avatar_url", "pro_purchased_at", "created_at", "updated_at" + ]; + + // Apply the Mask + textProperties.forEach(prop => { + if (typeof secured[prop] === "string") { + secured[prop] = maskCredential(secured[prop]); + } + }); + + return secured; +} + +/** Function to unmask the user object properties + * so the interface can read them safely without crashing. + */ +export function getDecryptedUser(user) { + if (!user) return null; + const decrypted = { ...user }; + + const textProperties = [ + "name", "role", "email", "github", "website", + "avatar_url", "pro_purchased_at", "created_at", "updated_at" + ]; + + textProperties.forEach(prop => { + if (Array.isArray(decrypted[prop])) { + decrypted[prop] = unmaskCredential(decrypted[prop]); + } + }); + + return decrypted; +} + class AuthService { #loginCallbacks = new Set(); #loginTimeout = null; @@ -105,17 +151,18 @@ class AuthService { * @returns {Promise} */ async getLoggedInUser(forceFetch = false) { - if (loggedInUser && !forceFetch) return loggedInUser; + if (loggedInUser && !forceFetch) return getDecryptedUser(loggedInUser); try { const res = await fetch(`${config.API_BASE}/login`); if (res.ok) { - loggedInUser = await res.json(); - localStorage.setItem(CACHE_USER_KEY, JSON.stringify(loggedInUser)); - clearTimeout(cacheTimeout); - cacheTimeout = setTimeout(() => (loggedInUser = null), 600_000); - return loggedInUser; + const rawuser = await res.json(); + loggedInUser = secureUserObject(rawuser); + localStorage.setItem(CACHE_USER_KEY, JSON.stringify(loggedInUser)); + clearTimeout(cacheTimeout); + cacheTimeout = setTimeout(() => (loggedInUser = null), 600_000); + return getDecryptedUser(loggedInUser); } if (res.status === 401) { diff --git a/src/security/security.js b/src/security/security.js new file mode 100644 index 000000000..7e3d29dc0 --- /dev/null +++ b/src/security/security.js @@ -0,0 +1,28 @@ +/** + * Copyright (C) dev12124 (dev brazilian, João Guilherme da Silva Freitas Lima), + * License: MIT license. + */ + +/** Variable for mask the Sensible Credentials of Acode, + * in JavaScript: Create a Variable (e.g: let key = "secret password"), + * this Variable is in the RAM (Random Access Memory) and a Malware-Plugin installed + * have access and modify the Variable. */ +const MASK_KEY = 0x5A; + +// The function to he apply a Mask +export function maskCredential(secretString) { + if (!secretString) return []; + + // Transforms the String in a Numbers Array (bytes) maskareds + return Array.from(secretString).map(char => char.charCodeAt(0) ^ MASK_KEY); +} + +// The Function to remove the Mask +export function unmaskCredential(maskedArray) { + if (!Array.isArray(maskedArray)) return " "; + + // Remove the Mask + return maskedArray + .map(byte => String.fromCharCode(byte ^ MASK_KEY)) + .join(""); +}