NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Random Password Generator
// @namespace https://openuserjs.org/users/burn
// @version 20261003
// @description Generate secure random password
// @copyright 2026, burn (https://openuserjs.org//users/burn)
// @license MIT
// @match *://*/*
// @noframes
// @include *
// @grant GM_registerMenuCommand
// @grant GM.registerMenuCommand
// @grant GM_setClipboard
// @grant GM.setClipboard
// ==/UserScript==
// ==OpenUserJS==
// @author burn
// ==/OpenUserJS==
/*jshint esversion: 8 */
(function() {
'use strict';
const DBG = false;
const SCRIPT = GM_info.script.name;
let log = (str) => {
DBG && console.log(SCRIPT + " | " + str);
};
const TOAST_DURATION = 5000; // ms
const TOAST_HOST_ID = "rpg-toast-host";
function secureRandomIndex(max) {
const range = 0xFFFFFFFF;
const limit = range - (range % max);
const buf = new Uint32Array(1);
do {
crypto.getRandomValues(buf);
} while (buf[0] >= limit);
return buf[0] % max;
}
function pick(str) {
return str[secureRandomIndex(str.length)];
}
function shuffle(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const j = secureRandomIndex(i + 1);
[arr[i], arr[j]] = [arr[j], arr[i]];
}
return arr;
}
function showToast(message) {
const old = document.getElementById(TOAST_HOST_ID);
if (old) old.remove();
const host = document.createElement("div");
host.id = TOAST_HOST_ID;
host.style.cssText = "all: initial; position: fixed; top: 20px; right: 20px; z-index: 2147483647;";
const shadow = host.attachShadow({ mode: "open" });
shadow.innerHTML = `
<style>
.toast {
position: relative;
box-sizing: border-box;
width: 320px;
max-width: calc(100vw - 40px);
padding: 16px 40px 20px 16px;
background: #1f2937;
color: #f9fafb;
font: 14px/1.4 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
border-radius: 8px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
overflow: hidden;
}
.close {
position: absolute;
top: 6px;
right: 6px;
width: 28px;
height: 28px;
padding: 0;
border: 0;
border-radius: 4px;
background: transparent;
color: #d1d5db;
font: 18px/28px system-ui, sans-serif;
text-align: center;
cursor: pointer;
}
.close:hover { background: rgba(255, 255, 255, 0.12); color: #fff; }
.close:focus-visible { outline: 2px solid #60a5fa; }
.bar {
position: absolute;
left: 0;
bottom: 0;
height: 5px;
width: 100%;
background: #22c55e;
animation: shrink ${TOAST_DURATION}ms linear forwards;
}
@keyframes shrink {
from { width: 100%; }
to { width: 0%; }
}
</style>
<div class="toast" role="status" aria-live="polite">
<span class="msg"></span>
<button class="close" type="button" aria-label="Chiudi">×</button>
<div class="bar"></div>
</div>
`;
shadow.querySelector(".msg").textContent = message;
const timer = setTimeout(close, TOAST_DURATION);
function close() {
clearTimeout(timer);
host.remove();
}
shadow.querySelector(".close").addEventListener("click", close);
(document.body || document.documentElement).appendChild(host);
}
function generatePassword() {
const LEN = 19;
const LOWER = "abcdefghijkmnopqrstuvwxyz"; // without lowercase l
const UPPER = "ABCDEFGHJKLMNPQRSTUVWXYZ"; // without uppercase O and uppercase I
const NUM = "23456789"; // without 0 and 1
const SYM = "!@#$%^&*()-_=+[]{};:,.<>?";
const ALL = LOWER + UPPER + NUM + SYM;
const result = new Array(
pick(LOWER),
pick(UPPER),
pick(NUM),
pick(SYM)
);
for (let i = result.length; i < LEN; i++) {
result.push(pick(ALL));
shuffle(result);
}
const password = result.join("");
let copied = false;
if (typeof GM_setClipboard !== "undefined") {
GM_setClipboard(password, "text");
copied = true;
} else if (typeof GM !== "undefined" && GM.setClipboard) {
GM.setClipboard(password, "text");
copied = true;
}
if (copied) {
showToast("Secure password copied into Clipboard!");
}
}
if (typeof GM_registerMenuCommand !== "undefined") {
GM_registerMenuCommand("Generate Secure Password", generatePassword);
} else if (typeof GM !== "undefined" && GM.registerMenuCommand) {
GM.registerMenuCommand("Generate Secure Password", generatePassword);
}
})();