ProtectLib.js Library Documentation
ProtectLib.js is a useful JavaScript library that serves as an efficient way of preventing and discouraging users from hacking the client side of web applications! You can manually direct it to protect the following aspects of your code from users and untrusted third-party scripts:
- Your DOM (Document Object Model)
- Your variables
- Your functions
- JavaScript's built in functions
You can test ProtectLib.js v1.0 at the ProtectLib.js Playground.
Warnings & Notices
- ProtectLib.js and its creator do not guarantee that it will block all hacks on the client side.
- ProtectLib.js is not designed to serve as the only protection for a web-based application, and should always be accompanied by thorough server-side security.
- All protections offered by the ProtectLib.js library will be rendered useless should the user disable the browser's JavaScript.
- ProtectLib.js does not protect the following aspects of your website:
- Access to the source code
- Access to the inspect menu
- The backend and its resources
- Changes to the attributes of the document element
- Frontend resources such as localStorage and sessionStorage
- The CSS (barring changes that occur in the `style` attribute of an element)
- Any variables and functions that you do not explicitly tell ProtectLib.js to defend
Installation
Before installing Protectlib.js in the<head>
tag of your HTML file, add this line of code:
<script>window.authorized = [];</script>
Inside the empty array
, add files that you want to have access to all Protectlib.js functions. The main HTML page is added automatically, so you do not have to add it. If you want to use a file in the same domain, you can access it by its relative filename. If you want to use a file in another domain, use its URL.Here is an example of an
array
that gives access for Protectlib.js functions to a file called example.js
and a file whose URL is https://example.com/example.js
:
<script>window.authorized = ["example.js", "https://example.com/example.js"];</script>
Once you have specified the permitted files, you can install ProtectLib.js in one of the following ways:
-
For easiest installation, you can import ProtectLib.js by its URL:
<script src="https://zacharym6.codewizardshq.com/libraries/protectlib/v1.0/protectlib.js"></script>
- Alternatively, you can download the ProtectLib.js JavaScript file (5.6 KB): Download Protectlib.js v1.0
-
If you would prefer, you can copy the code to paste into your program:
/* * Project Name: ProtectLib.js Library * Project Description: Make your websites more secure with this simple application to defend your code! * Project Version: 1.0 * Project Author: Z! (https://zacharym6.codewizardshq.com) * Project Documentation: https://zacharym6.codewizardshq.com/libraries/protectlib/v1.0/documentation */ function getFileNameSource() { try { throw Error(`There was a serious error!`); } catch (error) { var info = error.stack.split(`\n`)[error.stack.split(`\n`).length - 1].split(`at `)[1]; var iteration = 0; var newinfo = ``; if (info.startsWith(`<anonymous>`)) { return `<anonymous>`; } else { for (var section of info.split(`:`)) { if (iteration == 0) { newinfo += section + `:`; } else if (iteration == 1) { newinfo += section; } iteration += 1; } if (newinfo.includes(`(`)) { newinfo = newinfo.split(`(`)[1]; } return newinfo; } } } const getFileName = getFileNameSource; if (!window.authorized) { window.authorized = [document.documentURI, document.currentScript.src]; } else { window.authorized.push(document.documentURI); window.authorized.push(document.currentScript.src); } const __AUTHORIZED__ = protectVariable(CONVERTFILES(window.authorized), `*`, true); window.authorized = undefined; function CONVERTFILES(files) { if (files == `*`) { return files; } var newFiles = []; for (var file of files) { if (file.startsWith(`/`)) { file = `https://${document.domain}${file}`; } else if (!file.startsWith(`https`) && !file.startsWith(`<anonymous>`)) { var url = window.location.href.replace(window.location.href.split(`/`).pop(), ``); file = `${url}${file}`; } newFiles.push(file); } return newFiles; } function protectFunction(name, allowedFiles=__AUTHORIZED__.get()) { var sourceFile = getFileName(); try { if (!__AUTHORIZED__.get().includes(sourceFile)) { console.log(`Protect functions are exclusive to the primary HTML page!`); return undefined; } } catch (e) {} allowedFiles.push(document.currentScript.src); allowedFiles = CONVERTFILES(allowedFiles); eval(` var nextFunction = ${name}.bind(window); ${name} = function (...args) { console.log("This function has been protected by ProtectLib.js!"); }; `); var newFunction = nextFunction; nextFunction = undefined; return function(...args) { sourceFile = getFileName(); if (allowedFiles.includes(sourceFile) || allowedFiles == `*`) { return newFunction(...args); } else { console.log(`Access to function failed because ${sourceFile} is not allowed to access this resource.`); return undefined; } }; } function protectVariable(value, allowedFiles=__AUTHORIZED__.get(), constant=false) { var sourceFile = getFileName(); if (window.__AUTHORIZED__) { if (!__AUTHORIZED__.get().includes(sourceFile)) { console.log(`Protect functions are exclusive to the primary HTML page!`); return undefined; } } allowedFiles = CONVERTFILES(allowedFiles); var returnData; if (!constant) { returnData = { get: function() { sourceFile = getFileName(); if (allowedFiles.includes(sourceFile) || allowedFiles == `*`) { return value; } else { console.log(`Access to variable failed because ${sourceFile} is not allowed to access this resource.`); return undefined; } }, set: function(newValue) { sourceFile = getFileName(); if (allowedFiles.includes(sourceFile) || allowedFiles == `*`) { value = newValue; } else { console.log(`Access to variable failed because ${sourceFile} is not allowed to access this resource.`); } } }; } else { returnData = { get: function() { sourceFile = getFileName(); if (allowedFiles.includes(sourceFile) || allowedFiles == `*`) { return value; } else { console.log(`Access to variable failed because ${sourceFile} is not allowed to access this resource.`); return undefined; } } }; } Object.freeze(returnData); return returnData; } function protectDOM(accessFiles=__AUTHORIZED__.get()) { var sourceFile = getFileName(); if (!__AUTHORIZED__.get().includes(sourceFile)) { console.log(`Protect functions are exclusive to the primary HTML page!`); return undefined; } accessFiles = CONVERTFILES(accessFiles); var ignoreNextMutation = false; var lastSavedHTML = ``; const observer = new MutationObserver( function() { if (ignoreNextMutation) { ignoreNextMutation = false; } else { if (document.documentElement.innerHTML != lastSavedHTML) { document.documentElement.innerHTML = lastSavedHTML; } ignoreNextMutation = true; } } ); function pause() { sourceFile = getFileName(); if (accessFiles.includes(sourceFile) || accessFiles == `*`) { observer.disconnect(); } else { console.log(`Source ${sourceFile} is not permitted to access the DOM.`); } } function play() { sourceFile = getFileName(); if (accessFiles.includes(sourceFile) || accessFiles == `*`) { observer.observe(document.documentElement, { childList: true, attributes: true, characterData: true, subtree: true }); lastSavedHTML = document.documentElement.innerHTML; } else { console.log(`Source ${sourceFile} is not permitted to access the DOM.`); } } play(); var returnData = { pause: pause, play: play } Object.freeze(returnData); return returnData; }
getFileName()
Function
The getFileName()
function is used to get the file that a series of scripts started in.
Parameters
- None
Returns
- A
string
representing the file a series of scripts started in. Thestring
is the full URL of the file that the script was triggered in. Should a script have been triggered from the browser's Developer Tools, this function will return"<anonymous>"
.
Example Usage (from a file called example.html
in the same directory as this documentation)
// returns "https://zacharym6.codewizardshq.com/libraries/protectlib/v1.0/example.html"
getFileName();
Example Usage (from a file called example.html
in the same directory as this documentation)
<!-- returns "https://zacharym6.codewizardshq.com/libraries/protectlib/v1.0/example.html"
when the button is clicked -->
<button onclick="getFileName();">Click me!</button>
Example Usage (from a file called example.js
in the same directory as this documentation)
// returns "https://zacharym6.codewizardshq.com/libraries/protectlib/v1.0/example.js"
getFileName();
Example Usage (when called by the browser's Developer Tools)
// returns "<anonymous>"
getFileName();
Notes
- This function is not protected by ProtectLib.js. DO NOT USE PROTECTLIB.js TO PROTECT THIS FUNCTION, AS IT WILL CAUSE UNEXPECTED BEHAVIOR.
- As shown above, the function works even when executed from an attribute within an HTML tag.
- This function always returns the URL of the page that started a script. For example, if a script in
example.html
called a function inexample.js
and the function inexample.js
used this function, it would return the URL ofexample.html
.
protectDOM()
Function
The protectDOM()
function is used to prevent changes to the DOM (Document Object Model).
Parameters
accessFiles
- Anarray
containing all of the resources which are allowed to change the DOM. This parameter is optional, and defaults to the files which were permitted access before installation. IfaccessFiles
is set to"*"
, then any script, including the browser's Developer Tools, will be able to change the DOM.
Returns
- An
object
with two parameters:pause
andplay
. To learn about the usage of thisobject
, go to Accessing the DOM.
Example Usage
// Note the use of `const` in this instance. This prevents the object from being overridden by untrusted sources.
const domToggler = protectDOM(["example.js", "https://example.com/example.js"]);
Notes
- Once you have called this, any changes to the document will be blocked, including from trusted files.
protectFunction()
Function
The protectFunction()
function is used to prevent functions from being used by untrusted scripts.
Parameters
name
- Astring
containing the name of the function. You can also protect built-in functions, such asfetch()
.accessFiles
- Anarray
containing all of the resources which are allowed to call the function. This parameter is optional, and defaults to the files which were permitted access before installation. IfaccessFiles
is set to"*"
, then any script, including the browser's Developer Tools, will be able to call the function.
Returns
- A function with the same parameters and code as the original function. The difference is that the code is only run if the function is called from an allowed resource.
Example Usage
function testFunctionSource() {
console.log("This is a test!");
}
// Note the use of `const` in this instance. This prevents the function from being overridden by untrusted sources.
const testFunction = protectFunction("testFunctionSource", ["example.js", "https://example.com/example.js"]);
testFunctionSource(); // logs "This function has been protected by ProtectLib.js!"
testFunction(); // logs "This is a test!"
Notes
- Once you have called this, any calls to the new function will be blocked when it is called from an unspecified source.
protectVariable()
Function
The protectVariable()
function is used to prevent changes or access to a variable from untrusted sources.
Parameters
value
- The value of the variable. Can be any valid datatype.accessFiles
- Anarray
containing all of the resources which are allowed to access the variable. This parameter is optional, and defaults to the files which were permitted access before installation. IfaccessFiles
is set to"*"
, then any script, including the browser's Developer Tools, will be able to access the variable.constant
- Aboolean
that, if set totrue
, will prevent changes to the variable using.set()
. Defaults tofalse
.
Returns
- An object with a
get()
function. Ifconstant
was set tofalse
, the object will include aset()
function as well. To learn how to use these methods, go to ___.
Example Usage
// Note the use of `const` in this instance. This prevents the variable from being overridden by untrusted sources.
const myVariable = protectVariable("a string value", ["example.html", "example.js"], false);
Notes
- The variable will now be protected from untrusted sources. However, it cannot be accessed like a normal variable. See ___ to learn more about how to change the variable.
Accessing the DOM
If you used ProtectLib.js to defend your DOM, you probably will want to know how you can make changes to the DOM. In order to do so, you must use the object
which was returned by the protectDOM()
function.
To edit the DOM, you must follow these steps:
- Make sure you're accessing the DOM from a permitted file. This is the
accessFiles array
which was sent to theprotectDOM()
function. - Stop the DOM observer. This can be done by using the
pause()
function within theobject
which was returned by theprotectDOM()
function. - Make the intended changes to the elements.
- Restart the DOM observer. This can be done by using the
play()
function within theobject
which was returned by theprotectDOM()
function.
Here's an example script showing how you can edit the DOM using the above steps:
// define the DOM observer (assumes the file running this was granted permission in the window.authorized array)
const domToggler = protectDOM();
// stop the DOM observer
domToggler.pause();
// make the intended changes
document.querySelector("#edit-this-element").innerHTML += "<p>Changes were made to an element!</p>";
// restart the DOM observer
domToggler.play();
Accessing Variables
Getting a Variable
If you used ProtectLib.js to protect a variable using the protectVariable()
function, you can retrieve its value while in an allowed file with the .get()
function. Here's an example getting the value (false
) from a variable called gameOver
:
// Defining the variable
const gameOver = protectVariable(false, ["example.html"], true);
// Getting the variable's value (logs `false` to the console)
console.log(gameOver.get());
Setting a Variable
If you used ProtectLib.js to protect a variable using the protectVariable()
function, and you did not set the third parameter of the function to true
, then you can change the value of your variable in a permitted file. For example:
// Defining the variable
const userId = protectVariable(0, ["example.html"], false);
// Setting the variable's value to 1
userId.set(1);
// Getting the variable's new value (logs `1` to the console)
console.log(userId.get());